diff --git a/.buildkite/scripts/pipelines/pull_request/pipeline.ts b/.buildkite/scripts/pipelines/pull_request/pipeline.ts index 87ac7096e5a35..b1c877bb3db0e 100644 --- a/.buildkite/scripts/pipelines/pull_request/pipeline.ts +++ b/.buildkite/scripts/pipelines/pull_request/pipeline.ts @@ -250,7 +250,7 @@ const getPipeline = (filename: string, removeSteps = true) => { /^packages\/kbn-securitysolution-.*/, /^x-pack\/plugins\/alerting/, /^x-pack\/plugins\/data_views\/common/, - /^x-pack\/plugins\/lists/, + /^x-pack\/solutions\/security\/plugins\/lists/, /^x-pack\/plugins\/rule_registry\/common/, /^x-pack\/solutions\/security\/plugins\/security_solution/, /^x-pack\/solutions\/security\/plugins\/security_solution_ess/, @@ -306,10 +306,10 @@ const getPipeline = (filename: string, removeSteps = true) => { /^packages\/kbn-search-types/, /^packages\/kbn-securitysolution-.*/, /^src\/platform\/packages\/shared\/kbn-securitysolution-ecs/, - /^packages\/kbn-securitysolution-io-ts-alerting-types/, - /^packages\/kbn-securitysolution-io-ts-list-types/, - /^packages\/kbn-securitysolution-list-hooks/, - /^packages\/kbn-securitysolution-t-grid/, + /^x-pack\/solutions\/security\/packages\/kbn-securitysolution-io-ts-alerting-types/, + /^x-pack\/solutions\/security\/packages\/kbn-securitysolution-io-ts-list-types/, + /^x-pack\/solutions\/security\/packages\/kbn-securitysolution-list-hooks/, + /^x-pack\/solutions\/security\/packages\/kbn-securitysolution-t-grid/, /^packages\/kbn-ui-theme/, /^packages\/kbn-utility-types/, /^packages\/react/, @@ -335,7 +335,7 @@ const getPipeline = (filename: string, removeSteps = true) => { /^x-pack\/plugins\/cases/, /^x-pack\/plugins\/data_views\/common/, /^x-pack\/solutions\/security\/plugins\/elastic_assistant/, - /^x-pack\/plugins\/lists/, + /^x-pack\/solutions\/security\/plugins\/lists/, /^x-pack\/plugins\/rule_registry\/common/, /^x-pack\/solutions\/security\/plugins\/security_solution/, /^x-pack\/solutions\/security\/plugins\/security_solution_ess/, diff --git a/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh b/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh index db7131d127856..13bd0aaf7189a 100755 --- a/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh +++ b/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh @@ -10,13 +10,13 @@ echo -e "\n[Security Solution OpenAPI Code Generation] OpenAPI Common Package\n" (cd packages/kbn-openapi-common && yarn openapi:generate) echo -e "\n[Security Solution OpenAPI Code Generation] Lists Common Package\n" -(cd packages/kbn-securitysolution-lists-common && yarn openapi:generate) +(cd x-pack/solutions/security/packages/kbn-securitysolution-lists-common && yarn openapi:generate) echo -e "\n[Security Solution OpenAPI Code Generation] Exceptions Common Package\n" -(cd packages/kbn-securitysolution-exceptions-common && yarn openapi:generate) +(cd x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common && yarn openapi:generate) echo -e "\n[Security Solution OpenAPI Code Generation] Endpoint Exceptions Common Package\n" -(cd packages/kbn-securitysolution-endpoint-exceptions-common && yarn openapi:generate) +(cd x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common && yarn openapi:generate) echo -e "\n[Security Solution OpenAPI Code Generation] Security Solution Plugin\n" (cd x-pack/solutions/security/plugins/security_solution && yarn openapi:generate) diff --git a/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh index 18d2c963b3c24..4dd23435e351d 100755 --- a/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh +++ b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh @@ -16,13 +16,13 @@ echo -e "\n[Security Solution OpenAPI Bundling] Entity Analytics API\n" (cd x-pack/solutions/security/plugins/security_solution && yarn openapi:bundle:entity-analytics) echo -e "\n[Security Solution OpenAPI Bundling] Lists API\n" -(cd packages/kbn-securitysolution-lists-common && yarn openapi:bundle) +(cd x-pack/solutions/security/packages/kbn-securitysolution-lists-common && yarn openapi:bundle) echo -e "\n[Security Solution OpenAPI Bundling] Exceptions API\n" -(cd packages/kbn-securitysolution-exceptions-common && yarn openapi:bundle) +(cd x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common && yarn openapi:bundle) echo -e "\n[Security Solution OpenAPI Bundling] Endpoint Exceptions API\n" -(cd packages/kbn-securitysolution-endpoint-exceptions-common && yarn openapi:bundle) +(cd x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common && yarn openapi:bundle) echo -e "\n[Security Solution OpenAPI Bundling] Endpoint Management API\n" (cd x-pack/solutions/security/plugins/security_solution && yarn openapi:bundle:endpoint-management) diff --git a/.eslintrc.js b/.eslintrc.js index 6bf88444aaf70..93e3dabf3b861 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1343,8 +1343,8 @@ module.exports = { { // front end and common typescript and javascript files only files: [ - 'x-pack/plugins/lists/public/**/*.{js,mjs,ts,tsx}', - 'x-pack/plugins/lists/common/**/*.{js,mjs,ts,tsx}', + 'x-pack/solutions/security/plugins/lists/public/**/*.{js,mjs,ts,tsx}', + 'x-pack/solutions/security/plugins/lists/common/**/*.{js,mjs,ts,tsx}', ], rules: { 'import/no-nodejs-modules': 'error', @@ -1360,14 +1360,20 @@ module.exports = { }, { // typescript for /public and /common - files: ['x-pack/plugins/lists/public/*.{ts,tsx}', 'x-pack/plugins/lists/common/*.{ts,tsx}'], + files: [ + 'x-pack/solutions/security/plugins/lists/public/*.{ts,tsx}', + 'x-pack/solutions/security/plugins/lists/common/*.{ts,tsx}', + ], rules: { '@typescript-eslint/no-for-in-array': 'error', }, }, { // typescript for /public and /common - files: ['x-pack/plugins/lists/public/*.{ts,tsx}', 'x-pack/plugins/lists/common/*.{ts,tsx}'], + files: [ + 'x-pack/solutions/security/plugins/lists/public/*.{ts,tsx}', + 'x-pack/solutions/security/plugins/lists/common/*.{ts,tsx}', + ], plugins: ['react'], env: { jest: true, @@ -1425,7 +1431,7 @@ module.exports = { }, }, { - files: ['x-pack/plugins/lists/public/**/!(*.test).{js,mjs,ts,tsx}'], + files: ['x-pack/solutions/security/plugins/lists/public/**/!(*.test).{js,mjs,ts,tsx}'], plugins: ['react-perf'], rules: { 'react-perf/jsx-no-new-object-as-prop': 'error', @@ -1436,7 +1442,7 @@ module.exports = { }, { // typescript and javascript for front and back - files: ['x-pack/plugins/lists/**/*.{js,mjs,ts,tsx}'], + files: ['x-pack/solutions/security/plugins/lists/**/*.{js,mjs,ts,tsx}'], plugins: ['eslint-plugin-node'], env: { jest: true, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 83ddf30e9d9a5..315e5523c4c52 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -454,24 +454,6 @@ packages/kbn-search-index-documents @elastic/search-kibana packages/kbn-search-response-warnings @elastic/kibana-data-discovery packages/kbn-search-types @elastic/kibana-data-discovery packages/kbn-security-hardening @elastic/kibana-security -packages/kbn-securitysolution-autocomplete @elastic/security-detection-engine -packages/kbn-securitysolution-endpoint-exceptions-common @elastic/security-detection-engine -packages/kbn-securitysolution-es-utils @elastic/security-detection-engine -packages/kbn-securitysolution-exception-list-components @elastic/security-detection-engine -packages/kbn-securitysolution-exceptions-common @elastic/security-detection-engine -packages/kbn-securitysolution-hook-utils @elastic/security-detection-engine -packages/kbn-securitysolution-io-ts-alerting-types @elastic/security-detection-engine -packages/kbn-securitysolution-io-ts-list-types @elastic/security-detection-engine -packages/kbn-securitysolution-io-ts-types @elastic/security-detection-engine -packages/kbn-securitysolution-io-ts-utils @elastic/security-detection-engine -packages/kbn-securitysolution-list-api @elastic/security-detection-engine -packages/kbn-securitysolution-list-constants @elastic/security-detection-engine -packages/kbn-securitysolution-list-hooks @elastic/security-detection-engine -packages/kbn-securitysolution-list-utils @elastic/security-detection-engine -packages/kbn-securitysolution-lists-common @elastic/security-detection-engine -packages/kbn-securitysolution-rules @elastic/security-detection-engine -packages/kbn-securitysolution-t-grid @elastic/security-detection-engine -packages/kbn-securitysolution-utils @elastic/security-detection-engine packages/kbn-server-http-tools @elastic/kibana-core packages/kbn-set-map @elastic/kibana-operations packages/kbn-shared-svg @elastic/obs-ux-infra_services-team @@ -615,6 +597,10 @@ src/platform/packages/shared/kbn-management/settings/types @elastic/kibana-manag src/platform/packages/shared/kbn-management/settings/utilities @elastic/kibana-management src/platform/packages/shared/kbn-osquery-io-ts-types @elastic/security-asset-management src/platform/packages/shared/kbn-securitysolution-ecs @elastic/security-threat-hunting-explore +src/platform/packages/shared/kbn-securitysolution-es-utils @elastic/security-detection-engine +src/platform/packages/shared/kbn-securitysolution-io-ts-types @elastic/security-detection-engine +src/platform/packages/shared/kbn-securitysolution-io-ts-utils @elastic/security-detection-engine +src/platform/packages/shared/kbn-securitysolution-rules @elastic/security-detection-engine src/platform/packages/shared/kbn-server-route-repository @elastic/obs-knowledge-team src/platform/packages/shared/kbn-server-route-repository-client @elastic/obs-knowledge-team src/platform/packages/shared/kbn-server-route-repository-utils @elastic/obs-knowledge-team @@ -875,6 +861,7 @@ x-pack/platform/plugins/shared/license_management @elastic/kibana-management x-pack/platform/plugins/shared/ml @elastic/ml-ui x-pack/platform/plugins/shared/observability_solution/observability_ai_assistant @elastic/obs-ai-assistant x-pack/platform/plugins/shared/osquery @elastic/security-defend-workflows +x-pack/platform/plugins/shared/screenshotting @elastic/kibana-reporting-services x-pack/platform/plugins/shared/searchprofiler @elastic/kibana-management x-pack/plugins/actions @elastic/response-ops x-pack/plugins/alerting @elastic/response-ops @@ -906,7 +893,6 @@ x-pack/plugins/graph @elastic/kibana-visualizations x-pack/plugins/index_management @elastic/kibana-management x-pack/plugins/lens @elastic/kibana-visualizations x-pack/plugins/licensing @elastic/kibana-core -x-pack/plugins/lists @elastic/security-detection-engine x-pack/plugins/logstash @elastic/logstash x-pack/plugins/maps @elastic/kibana-presentation x-pack/plugins/monitoring @elastic/stack-monitoring @@ -931,7 +917,6 @@ x-pack/plugins/observability_solution/profiling_data_access @elastic/obs-ux-infr x-pack/plugins/reporting @elastic/appex-sharedux x-pack/plugins/rule_registry @elastic/response-ops @elastic/obs-ux-management-team x-pack/plugins/saved_objects_tagging @elastic/appex-sharedux -x-pack/plugins/screenshotting @elastic/kibana-reporting-services x-pack/plugins/search_assistant @elastic/search-kibana x-pack/plugins/search_connectors @elastic/search-kibana x-pack/plugins/search_homepage @elastic/search-kibana @@ -986,6 +971,20 @@ x-pack/solutions/security/packages/features @elastic/security-threat-hunting-exp x-pack/solutions/security/packages/index-adapter @elastic/security-threat-hunting x-pack/solutions/security/packages/kbn-cloud-security-posture/graph @elastic/kibana-cloud-security-posture x-pack/solutions/security/packages/kbn-cloud-security-posture/public @elastic/kibana-cloud-security-posture +x-pack/solutions/security/packages/kbn-securitysolution-autocomplete @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-hook-utils @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-list-api @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-list-constants @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-list-hooks @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-list-utils @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-lists-common @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-t-grid @elastic/security-detection-engine +x-pack/solutions/security/packages/kbn-securitysolution-utils @elastic/security-detection-engine x-pack/solutions/security/packages/navigation @elastic/security-threat-hunting-explore x-pack/solutions/security/packages/side_nav @elastic/security-threat-hunting-explore x-pack/solutions/security/packages/storybook/config @elastic/security-threat-hunting-explore @@ -996,6 +995,7 @@ x-pack/solutions/security/plugins/cloud_security_posture @elastic/kibana-cloud-s x-pack/solutions/security/plugins/ecs_data_quality_dashboard @elastic/security-threat-hunting-explore x-pack/solutions/security/plugins/elastic_assistant @elastic/security-generative-ai x-pack/solutions/security/plugins/kubernetes_security @elastic/kibana-cloud-security-posture +x-pack/solutions/security/plugins/lists @elastic/security-detection-engine x-pack/solutions/security/plugins/security_solution @elastic/security-solution x-pack/solutions/security/plugins/security_solution_ess @elastic/security-solution x-pack/solutions/security/plugins/security_solution_serverless @elastic/security-solution @@ -3354,20 +3354,20 @@ x-pack/solutions/security/packages/kbn-cloud-security-posture/public @elastic/ki x-pack/solutions/security/packages/data-stream-adapter @elastic/security-threat-hunting x-pack/solutions/security/packages/expandable-flyout @elastic/security-threat-hunting-investigations x-pack/solutions/security/packages/index-adapter @elastic/security-threat-hunting -x-pack/solutions/security/packages/kbn-securitysolution-autocomplete @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-hook-utils @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-list-api @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-list-constants @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-list-hooks @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-list-utils @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-lists-common @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-t-grid @elastic/security-detection-engine -x-pack/solutions/security/packages/kbn-securitysolution-utils @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-list-api @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-list-constants @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-list-utils @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-lists-common @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-t-grid @elastic/security-detection-engine +x-pack/solutions/security/x-pack/solutions/security/packages/kbn-securitysolution-utils @elastic/security-detection-engine x-pack/solutions/security/packages/navigation @elastic/security-threat-hunting-explore x-pack/solutions/security/packages/side_nav @elastic/security-threat-hunting-explore x-pack/solutions/security/packages/upselling @elastic/security-threat-hunting-explore @@ -3377,7 +3377,7 @@ x-pack/solutions/security/plugins/cloud_security_posture @elastic/kibana-cloud-s x-pack/solutions/security/plugins/ecs_data_quality_dashboard @elastic/security-threat-hunting-explore x-pack/solutions/security/plugins/elastic_assistant @elastic/security-generative-ai x-pack/solutions/security/plugins/kubernetes_security @elastic/kibana-cloud-security-posture -x-pack/solutions/security/plugins/lists @elastic/security-detection-engine +x-pack/solutions/security/solutions/security/plugins/lists @elastic/security-detection-engine x-pack/solutions/security/solutions/security/plugins/security_solution @elastic/security-solution x-pack/solutions/security/solutions/security/plugins/security_solution_ess @elastic/security-solution x-pack/solutions/security/solutions/security/plugins/security_solution_serverless @elastic/security-solution diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 8ad946732714b..3077ac0f51674 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -78,8 +78,8 @@ paths-ignore: - x-pack/solutions/security/plugins/elastic_assistant/scripts - x-pack/plugins/event_log/scripts - x-pack/plugins/fleet/scripts - - x-pack/plugins/lists/scripts - - x-pack/plugins/lists/server/scripts + - x-pack/solutions/security/plugins/lists/scripts + - x-pack/solutions/security/plugins/lists/server/scripts - x-pack/plugins/observability_solution/*/scripts - x-pack/platform/plugins/shared/osquery/scripts - x-pack/plugins/rule_registry/scripts diff --git a/.i18nrc.json b/.i18nrc.json index 63cbc62d13650..0e167c2b08b54 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -6,7 +6,7 @@ "alertsUIShared": "packages/kbn-alerts-ui-shared/src", "alertingTypes": "packages/kbn-alerting-types", "apmOss": "src/plugins/apm_oss", - "autocomplete": "packages/kbn-securitysolution-autocomplete/src", + "autocomplete": "x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src", "avcBanner": "src/platform/packages/shared/kbn-avc-banner/src", "bfetch": "src/plugins/bfetch", "bfetchError": "packages/kbn-bfetch-error", @@ -25,12 +25,13 @@ "data": "src/plugins/data", "observabilityAlertDetails": "x-pack/solutions/observability/packages/alert_details", "dataViews": "src/plugins/data_views", - "defaultNavigation": [ - "packages/default-nav", - "src/platform/packages/private/default-nav" - ], + "defaultNavigation": ["packages/default-nav", "src/platform/packages/private/default-nav"], "devTools": "src/platform/plugins/shared/dev_tools", - "discover": ["src/plugins/discover", "packages/kbn-discover-utils", "packages/kbn-discover-contextual-components"], + "discover": [ + "src/plugins/discover", + "packages/kbn-discover-utils", + "packages/kbn-discover-contextual-components" + ], "savedSearch": "src/plugins/saved_search", "embeddableApi": "src/plugins/embeddable", "presentationPanel": "src/plugins/presentation_panel", @@ -87,8 +88,8 @@ "kibana-react": "src/plugins/kibana_react", "kibanaOverview": "src/plugins/kibana_overview", "lensFormulaDocs": "packages/kbn-lens-formula-docs", - "lists": "packages/kbn-securitysolution-list-utils/src", - "exceptionList-components": "packages/kbn-securitysolution-exception-list-components/src", + "lists": "x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src", + "exceptionList-components": "x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src", "management": [ "src/platform/plugins/shared/management", "src/platform/packages/private/kbn-management", @@ -120,11 +121,15 @@ "searchResponseWarnings": "packages/kbn-search-response-warnings", "searchTypes": "packages/kbn-search-types", "securitySolutionPackages": [ - "x-pack/solutions/security/packages" - ], - "sharedPlatformPackages": [ - "x-pack/platform/packages/shared/kbn-cloud-security-posture" + "x-pack/solutions/security/packages/data_table", + "x-pack/solutions/security/packages/ecs_data_quality_dashboard", + "x-pack/solutions/security/packages/features", + "x-pack/solutions/security/packages/kbn-cloud-security-posture", + "x-pack/solutions/security/packages/navigation", + "x-pack/solutions/security/packages/side_nav", + "x-pack/solutions/security/packages/upselling" ], + "sharedPlatformPackages": ["x-pack/platform/packages/shared/kbn-cloud-security-posture"], "serverlessPackages": "packages/serverless", "sse": ["src/platform/packages/shared/kbn-sse-utils"], "coloring": "packages/kbn-coloring/src", @@ -140,7 +145,7 @@ "uiActionsExamples": "examples/ui_action_examples", "usageCollection": "src/plugins/usage_collection", "userProfileComponents": "packages/kbn-user-profile-components", - "utils": "packages/kbn-securitysolution-utils/src", + "utils": "x-pack/solutions/security/packages/kbn-securitysolution-utils/src", "visDefaultEditor": "src/plugins/vis_default_editor", "visTypeGauge": "src/plugins/vis_types/gauge", "visTypeHeatmap": "src/plugins/vis_types/heatmap", diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index dd2678d032fbf..9ee9015aed0b1 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -693,7 +693,7 @@ the infrastructure monitoring use-case within Kibana. |The licensing plugin retrieves license data from Elasticsearch at regular configurable intervals. -|{kib-repo}blob/{branch}/x-pack/plugins/lists/README.md[lists] +|{kib-repo}blob/{branch}/x-pack/solutions/security/plugins/lists/README.md[lists] |README.md for developers working on the backend lists on how to get started using the CURL scripts in the scripts folder. @@ -815,7 +815,7 @@ Elastic. |Add tagging capability to saved objects -|{kib-repo}blob/{branch}/x-pack/plugins/screenshotting/README.md[screenshotting] +|{kib-repo}blob/{branch}/x-pack/platform/plugins/shared/screenshotting/README.md[screenshotting] |This plugin provides functionality to take screenshots of the Kibana pages. It uses Chromium and Puppeteer underneath to run the browser in headless mode. diff --git a/oas_docs/scripts/merge_ess_oas.js b/oas_docs/scripts/merge_ess_oas.js index 3d96ad5b5933f..df0b6e5a4ac04 100644 --- a/oas_docs/scripts/merge_ess_oas.js +++ b/oas_docs/scripts/merge_ess_oas.js @@ -27,9 +27,9 @@ const { REPO_ROOT } = require('@kbn/repo-info'); // Security solution `${REPO_ROOT}/x-pack/solutions/security/plugins/security_solution/docs/openapi/ess/*.schema.yaml`, - `${REPO_ROOT}/packages/kbn-securitysolution-lists-common/docs/openapi/ess/*.schema.yaml`, - `${REPO_ROOT}/packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/*.schema.yaml`, - `${REPO_ROOT}/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/*.schema.yaml`, + `${REPO_ROOT}/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/docs/openapi/ess/*.schema.yaml`, + `${REPO_ROOT}/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/*.schema.yaml`, + `${REPO_ROOT}/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/*.schema.yaml`, `${REPO_ROOT}/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/ess/*.schema.yaml`, `${REPO_ROOT}/x-pack/platform/plugins/shared/osquery/docs/openapi/ess/*.schema.yaml`, ], diff --git a/oas_docs/scripts/merge_serverless_oas.js b/oas_docs/scripts/merge_serverless_oas.js index 2f92195502db1..343487d8fc4f8 100644 --- a/oas_docs/scripts/merge_serverless_oas.js +++ b/oas_docs/scripts/merge_serverless_oas.js @@ -25,9 +25,9 @@ const { REPO_ROOT } = require('@kbn/repo-info'); // Security solution `${REPO_ROOT}/x-pack/solutions/security/plugins/security_solution/docs/openapi/serverless/*.schema.yaml`, - `${REPO_ROOT}/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/*.schema.yaml`, - `${REPO_ROOT}/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/*.schema.yaml`, - `${REPO_ROOT}/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/*.schema.yaml`, + `${REPO_ROOT}/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/*.schema.yaml`, + `${REPO_ROOT}/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/*.schema.yaml`, + `${REPO_ROOT}/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/*.schema.yaml`, `${REPO_ROOT}/x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/serverless/*.schema.yaml`, `${REPO_ROOT}/x-pack/platform/plugins/shared/osquery/docs/openapi/serverless/*.schema.yaml`, ], diff --git a/package.json b/package.json index a71ee7623bdc9..c9556bc248f19 100644 --- a/package.json +++ b/package.json @@ -619,7 +619,7 @@ "@kbn/license-management-plugin": "link:x-pack/platform/plugins/shared/license_management", "@kbn/licensing-plugin": "link:x-pack/plugins/licensing", "@kbn/links-plugin": "link:src/plugins/links", - "@kbn/lists-plugin": "link:x-pack/plugins/lists", + "@kbn/lists-plugin": "link:x-pack/solutions/security/plugins/lists", "@kbn/llm-tasks-plugin": "link:x-pack/platform/plugins/shared/ai_infra/llm_tasks", "@kbn/locator-examples-plugin": "link:examples/locator_examples", "@kbn/locator-explorer-plugin": "link:examples/locator_explorer", @@ -796,7 +796,7 @@ "@kbn/screenshot-mode-example-plugin": "link:examples/screenshot_mode_example", "@kbn/screenshot-mode-plugin": "link:src/plugins/screenshot_mode", "@kbn/screenshotting-example-plugin": "link:x-pack/examples/screenshotting_example", - "@kbn/screenshotting-plugin": "link:x-pack/plugins/screenshotting", + "@kbn/screenshotting-plugin": "link:x-pack/platform/plugins/shared/screenshotting", "@kbn/screenshotting-server": "link:packages/kbn-screenshotting-server", "@kbn/search-api-keys-components": "link:packages/kbn-search-api-keys-components", "@kbn/search-api-keys-server": "link:packages/kbn-search-api-keys-server", @@ -839,26 +839,26 @@ "@kbn/security-solution-upselling": "link:x-pack/solutions/security/packages/upselling", "@kbn/security-test-endpoints-plugin": "link:x-pack/test/security_functional/plugins/test_endpoints", "@kbn/security-ui-components": "link:x-pack/packages/security/ui_components", - "@kbn/securitysolution-autocomplete": "link:packages/kbn-securitysolution-autocomplete", + "@kbn/securitysolution-autocomplete": "link:x-pack/solutions/security/packages/kbn-securitysolution-autocomplete", "@kbn/securitysolution-data-table": "link:x-pack/solutions/security/packages/data_table", "@kbn/securitysolution-ecs": "link:src/platform/packages/shared/kbn-securitysolution-ecs", - "@kbn/securitysolution-endpoint-exceptions-common": "link:packages/kbn-securitysolution-endpoint-exceptions-common", - "@kbn/securitysolution-es-utils": "link:packages/kbn-securitysolution-es-utils", - "@kbn/securitysolution-exception-list-components": "link:packages/kbn-securitysolution-exception-list-components", - "@kbn/securitysolution-exceptions-common": "link:packages/kbn-securitysolution-exceptions-common", - "@kbn/securitysolution-hook-utils": "link:packages/kbn-securitysolution-hook-utils", - "@kbn/securitysolution-io-ts-alerting-types": "link:packages/kbn-securitysolution-io-ts-alerting-types", - "@kbn/securitysolution-io-ts-list-types": "link:packages/kbn-securitysolution-io-ts-list-types", - "@kbn/securitysolution-io-ts-types": "link:packages/kbn-securitysolution-io-ts-types", - "@kbn/securitysolution-io-ts-utils": "link:packages/kbn-securitysolution-io-ts-utils", - "@kbn/securitysolution-list-api": "link:packages/kbn-securitysolution-list-api", - "@kbn/securitysolution-list-constants": "link:packages/kbn-securitysolution-list-constants", - "@kbn/securitysolution-list-hooks": "link:packages/kbn-securitysolution-list-hooks", - "@kbn/securitysolution-list-utils": "link:packages/kbn-securitysolution-list-utils", - "@kbn/securitysolution-lists-common": "link:packages/kbn-securitysolution-lists-common", - "@kbn/securitysolution-rules": "link:packages/kbn-securitysolution-rules", - "@kbn/securitysolution-t-grid": "link:packages/kbn-securitysolution-t-grid", - "@kbn/securitysolution-utils": "link:packages/kbn-securitysolution-utils", + "@kbn/securitysolution-endpoint-exceptions-common": "link:x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common", + "@kbn/securitysolution-es-utils": "link:src/platform/packages/shared/kbn-securitysolution-es-utils", + "@kbn/securitysolution-exception-list-components": "link:x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components", + "@kbn/securitysolution-exceptions-common": "link:x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common", + "@kbn/securitysolution-hook-utils": "link:x-pack/solutions/security/packages/kbn-securitysolution-hook-utils", + "@kbn/securitysolution-io-ts-alerting-types": "link:x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types", + "@kbn/securitysolution-io-ts-list-types": "link:x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types", + "@kbn/securitysolution-io-ts-types": "link:src/platform/packages/shared/kbn-securitysolution-io-ts-types", + "@kbn/securitysolution-io-ts-utils": "link:src/platform/packages/shared/kbn-securitysolution-io-ts-utils", + "@kbn/securitysolution-list-api": "link:x-pack/solutions/security/packages/kbn-securitysolution-list-api", + "@kbn/securitysolution-list-constants": "link:x-pack/solutions/security/packages/kbn-securitysolution-list-constants", + "@kbn/securitysolution-list-hooks": "link:x-pack/solutions/security/packages/kbn-securitysolution-list-hooks", + "@kbn/securitysolution-list-utils": "link:x-pack/solutions/security/packages/kbn-securitysolution-list-utils", + "@kbn/securitysolution-lists-common": "link:x-pack/solutions/security/packages/kbn-securitysolution-lists-common", + "@kbn/securitysolution-rules": "link:src/platform/packages/shared/kbn-securitysolution-rules", + "@kbn/securitysolution-t-grid": "link:x-pack/solutions/security/packages/kbn-securitysolution-t-grid", + "@kbn/securitysolution-utils": "link:x-pack/solutions/security/packages/kbn-securitysolution-utils", "@kbn/server-http-tools": "link:packages/kbn-server-http-tools", "@kbn/server-route-repository": "link:src/platform/packages/shared/kbn-server-route-repository", "@kbn/server-route-repository-client": "link:src/platform/packages/shared/kbn-server-route-repository-client", diff --git a/packages/core/http/core-http-server-internal/src/http_config.test.ts b/packages/core/http/core-http-server-internal/src/http_config.test.ts index 4ba13489552bd..fa2fbe7ad9f36 100644 --- a/packages/core/http/core-http-server-internal/src/http_config.test.ts +++ b/packages/core/http/core-http-server-internal/src/http_config.test.ts @@ -517,9 +517,9 @@ describe('versioned', () => { ).toThrow(/failed validation/); }); - it('defaults version resolution "none" when in dev', () => { + it('defaults version resolution "oldest" when in dev', () => { expect(config.schema.validate({}, { dev: true })).toMatchObject({ - versioned: { versionResolution: 'none' }, + versioned: { versionResolution: 'oldest' }, }); }); }); diff --git a/packages/core/http/core-http-server-internal/src/http_config.ts b/packages/core/http/core-http-server-internal/src/http_config.ts index 11c1afc410331..4ba9bcb9e88be 100644 --- a/packages/core/http/core-http-server-internal/src/http_config.ts +++ b/packages/core/http/core-http-server-internal/src/http_config.ts @@ -213,7 +213,7 @@ const configSchema = schema.object( * Which handler resolution algo to use for public routes: "newest" or "oldest". * * @note Internal routes always require a version to be specified. - * @note in development we have an additional option "none" which is also the default in dev. + * @note in development we have an additional option "none". * This prevents any fallbacks and requires that a version specified. * Useful for ensuring that a given client always specifies a version. */ @@ -221,7 +221,7 @@ const configSchema = schema.object( schema.contextRef('dev'), true, schema.oneOf([schema.literal('newest'), schema.literal('oldest'), schema.literal('none')], { - defaultValue: 'none', + defaultValue: 'oldest', }), schema.oneOf([schema.literal('newest'), schema.literal('oldest')], { defaultValue: 'oldest', diff --git a/packages/kbn-babel-preset/styled_components_files.js b/packages/kbn-babel-preset/styled_components_files.js index 2a74c5b60f181..60dbb2b1053de 100644 --- a/packages/kbn-babel-preset/styled_components_files.js +++ b/packages/kbn-babel-preset/styled_components_files.js @@ -16,12 +16,13 @@ module.exports = { /packages[\/\\]kbn-ui-shared-deps-(npm|src)[\/\\]/, /src[\/\\]plugins[\/\\](kibana_react)[\/\\]/, /x-pack[\/\\]solutions[\/\\]observability[\/\\]plugins[\/\\](exploratory_view|investigate|investigate_app|observability|observability_ai_assistant_app|observability_ai_assistant_management|observability_solution|serverless_observability|streams|streams_app|synthetics|uptime|ux)[\/\\]/, - /x-pack[\/\\]plugins[\/\\](observability_solution\/apm|beats_management|fleet|lists|observability_solution\/observability|observability_solution\/observability_shared|observability_solution\/exploratory_view|security_solution|timelines|observability_solution\/synthetics|observability_solution\/ux|observability_solution\/uptime)[\/\\]/, + /x-pack[\/\\]plugins[\/\\](observability_solution\/apm|beats_management|fleet|observability_solution\/observability|observability_solution\/observability_shared|observability_solution\/exploratory_view|security_solution|timelines|observability_solution\/synthetics|observability_solution\/ux|observability_solution\/uptime)[\/\\]/, /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\](observability_solution\/apm|beats_management|fleet|observability_solution\/infra|lists|observability_solution\/observability|observability_solution\/observability_shared|observability_solution\/exploratory_view|security_solution|timelines|observability_solution\/synthetics|observability_solution\/ux|observability_solution\/uptime)[\/\\]/, /x-pack[\/\\]test[\/\\]plugin_functional[\/\\]plugins[\/\\]resolver_test[\/\\]/, /x-pack[\/\\]packages[\/\\]elastic_assistant[\/\\]/, /x-pack[\/\\]solutions[\/\\]security[\/\\]packages[\/\\]ecs_data_quality_dashboard[\/\\]/, /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]security_solution[\/\\]/, /x-pack[\/\\]platform[\/\\]packages[\/\\]shared[\/\\]kbn-elastic-assistant[\/\\]/, + /x-pack[\/\\]solutions[\/\\]security[\/\\]plugins[\/\\]lists/, ], }; diff --git a/packages/kbn-cli-dev-mode/src/watcher.ts b/packages/kbn-cli-dev-mode/src/watcher.ts index 6dc11371d9582..193458495aa21 100644 --- a/packages/kbn-cli-dev-mode/src/watcher.ts +++ b/packages/kbn-cli-dev-mode/src/watcher.ts @@ -19,7 +19,7 @@ import { Log } from './log'; const packageMatcher = makeMatcher([ '**/*', '!**/.*', - '!x-pack/plugins/screenshotting/chromium/**', + '!x-pack/platform/plugins/shared/screenshotting/chromium/**', '!x-pack/plugins/canvas/shareable_runtime/**', ]); diff --git a/packages/kbn-search-api-panels/components/cloud_details.tsx b/packages/kbn-search-api-panels/components/cloud_details.tsx index df2cc6bb6837d..0c406b4c31855 100644 --- a/packages/kbn-search-api-panels/components/cloud_details.tsx +++ b/packages/kbn-search-api-panels/components/cloud_details.tsx @@ -97,7 +97,7 @@ export const CloudDetailsPanel = ({ - + /packages/kbn-securitysolution-autocomplete'], -}; diff --git a/packages/kbn-securitysolution-autocomplete/package.json b/packages/kbn-securitysolution-autocomplete/package.json deleted file mode 100644 index f841706e57a7e..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@kbn/securitysolution-autocomplete", - "version": "1.0.0", - "description": "Security Solution auto complete", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true, - "sideEffects": false -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-autocomplete/src/autocomplete/index.mock.ts b/packages/kbn-securitysolution-autocomplete/src/autocomplete/index.mock.ts deleted file mode 100644 index 71bfb7f4a67cd..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/autocomplete/index.mock.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -// Copied from "src/plugins/data/public/mocks.ts" but without any type information -// TODO: Remove this in favor of the data/public/mocks if/when they become available, https://github.com/elastic/kibana/issues/100715 -export const autocompleteStartMock = { - getQuerySuggestions: jest.fn(), - getValueSuggestions: jest.fn(), - hasQuerySuggestions: jest.fn(), -}; diff --git a/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.test.ts b/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.test.ts deleted file mode 100644 index d98feca80b75b..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { checkEmptyValue } from '.'; -import { getField } from '../fields/index.mock'; -import * as i18n from '../translations'; - -describe('check_empty_value', () => { - test('returns no errors if no field has been selected', () => { - const isValid = checkEmptyValue('', undefined, true, false); - - expect(isValid).toBeUndefined(); - }); - - test('returns error string if user has touched a required input and left empty', () => { - const isValid = checkEmptyValue(undefined, getField('@timestamp'), true, true); - - expect(isValid).toEqual(i18n.FIELD_REQUIRED_ERR); - }); - - test('returns no errors if required input is empty but user has not yet touched it', () => { - const isValid = checkEmptyValue(undefined, getField('@timestamp'), true, false); - - expect(isValid).toBeUndefined(); - }); - - test('returns no errors if user has touched an input that is not required and left empty', () => { - const isValid = checkEmptyValue(undefined, getField('@timestamp'), false, true); - - expect(isValid).toBeUndefined(); - }); - - test('returns no errors if user has touched an input that is not required and left empty string', () => { - const isValid = checkEmptyValue('', getField('@timestamp'), false, true); - - expect(isValid).toBeUndefined(); - }); - - test('returns null if input value is not empty string or undefined', () => { - const isValid = checkEmptyValue('hellooo', getField('@timestamp'), false, true); - - expect(isValid).toBeNull(); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.ts b/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.ts deleted file mode 100644 index 218b8fee94d1e..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DataViewFieldBase } from '@kbn/es-query'; -import * as i18n from '../translations'; - -/** - * Determines if empty value is ok - */ -export const checkEmptyValue = ( - param: string | undefined, - field: DataViewFieldBase | undefined, - isRequired: boolean, - touched: boolean -): string | undefined | null => { - if (isRequired && touched && (param == null || param.trim() === '')) { - return i18n.FIELD_REQUIRED_ERR; - } - - if ( - field == null || - (isRequired && !touched) || - (!isRequired && (param == null || param === '')) - ) { - return undefined; - } - - return null; -}; diff --git a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/disabled_types_with_tooltip_text.test.ts b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/disabled_types_with_tooltip_text.test.ts deleted file mode 100644 index 980819d1cedf1..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/disabled_types_with_tooltip_text.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { disabledTypesWithTooltipText } from '../disabled_types_with_tooltip_text'; - -jest.mock('../../translations', () => ({ - BINARY_TYPE_NOT_SUPPORTED: 'Binary fields are currently unsupported', -})); -describe('disabledTypesWithTooltipText', () => { - it('should return Binary fields are currently unsupported for binary type', () => { - const type = 'binary'; - expect(disabledTypesWithTooltipText[type]).toEqual('Binary fields are currently unsupported'); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/index.test.tsx deleted file mode 100644 index 1b33b4b294644..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/index.test.tsx +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { fireEvent, render, waitFor, within } from '@testing-library/react'; -import '@testing-library/jest-dom'; - -import { EsFieldSelector } from '..'; -import { fields, getField } from '../../fields/index.mock'; - -describe('FieldComponent', () => { - it('should render the component enabled and displays the selected field correctly', () => { - const wrapper = render( - - ); - expect(wrapper.container).toMatchSnapshot(); - const comboBox = wrapper.getByTestId('fieldAutocompleteComboBox'); - const input = within(comboBox).getByRole('combobox'); - expect(input).toHaveAttribute('value', 'machine.os.raw'); - }); - it('should render the component disabled if isDisabled is true', () => { - const wrapper = render( - - ); - expect(wrapper.container).toMatchSnapshot(); - expect(wrapper.getByTestId('fieldAutocompleteComboBox').querySelector('input')).toBeDisabled(); - }); - it('should render the loading spinner if isLoading is true when clicked', () => { - const wrapper = render( - - ); - const fieldAutocompleteComboBox = wrapper.getByTestId('fieldAutocompleteComboBox'); - expect(wrapper.container).toMatchSnapshot(); - fireEvent.click(fieldAutocompleteComboBox); - expect(wrapper.getByRole('progressbar')).toBeInTheDocument(); - }); - it('should allow user to clear values if isClearable is true', () => { - const wrapper = render( - - ); - expect(wrapper.container).toMatchSnapshot(); - expect(wrapper.getByTestId('comboBoxClearButton')).toBeInTheDocument(); - }); - it('should change the selected value', async () => { - const wrapper = render( - - ); - const fieldAutocompleteComboBox = wrapper.getByTestId('comboBoxSearchInput'); - fireEvent.change(fieldAutocompleteComboBox, { target: { value: '_source' } }); - expect(fieldAutocompleteComboBox).toHaveValue('_source'); - }); - - it('it allows custom user input if "acceptsCustomOptions" is "true"', async () => { - const mockOnChange = jest.fn(); - const wrapper = render( - - ); - - const fieldAutocompleteComboBox = wrapper.getByTestId('comboBoxSearchInput'); - fireEvent.change(fieldAutocompleteComboBox, { target: { value: 'custom' } }); - await waitFor(() => - expect(wrapper.getByTestId('fieldAutocompleteComboBox')).toHaveTextContent('custom') - ); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/disabled_types_with_tooltip_text.ts b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/disabled_types_with_tooltip_text.ts deleted file mode 100644 index 422a909bb9910..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/disabled_types_with_tooltip_text.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -interface DisabledTypesTextType { - [typeName: string]: string; -} -import * as i18n from '../translations'; - -export const disabledTypesWithTooltipText: DisabledTypesTextType = { - binary: i18n.BINARY_TYPE_NOT_SUPPORTED, -}; diff --git a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/index.tsx b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/index.tsx deleted file mode 100644 index 31efaa23b62df..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/index.tsx +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { EuiComboBox } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { FieldBaseProps } from './types'; -import { useEsField } from './use_es_field'; - -const AS_PLAIN_TEXT = { asPlainText: true }; - -interface EsFieldSelectorProps extends FieldBaseProps { - isClearable?: boolean; - isDisabled?: boolean; - isLoading?: boolean; - placeholder: string; - acceptsCustomOptions?: boolean; - showMappingConflicts?: boolean; - 'aria-label'?: string; -} - -export function EsFieldSelector({ - fieldInputWidth, - fieldTypeFilter = [], - indexPattern, - isClearable = false, - isDisabled = false, - isLoading = false, - isRequired = false, - onChange, - placeholder, - selectedField, - acceptsCustomOptions = false, - showMappingConflicts = false, - 'aria-label': ariaLabel, -}: EsFieldSelectorProps): JSX.Element { - const { - isInvalid, - comboOptions, - selectedComboOptions, - fieldWidth, - renderFields, - handleTouch, - handleValuesChange, - handleCreateCustomOption, - } = useEsField({ - indexPattern, - fieldTypeFilter, - isRequired, - selectedField, - fieldInputWidth, - showMappingConflicts, - onChange, - }); - - if (acceptsCustomOptions) { - return ( - - ); - } - - return ( - - ); -} diff --git a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/types.ts b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/types.ts deleted file mode 100644 index b0f1ab56e8079..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/types.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; -import { FieldConflictsInfo } from '@kbn/securitysolution-list-utils'; -import { GetGenericComboBoxPropsReturn } from '../get_generic_combo_box_props'; - -export interface FieldBaseProps { - indexPattern: DataViewBase | undefined; - fieldTypeFilter?: string[]; - isRequired?: boolean; - selectedField?: DataViewFieldBase | undefined; - fieldInputWidth?: number; - showMappingConflicts?: boolean; - onChange: (a: DataViewFieldBase[]) => void; -} - -export interface ComboBoxFields { - availableFields: DataViewField[]; - selectedFields: DataViewField[]; -} - -export interface GetFieldComboBoxPropsReturn extends GetGenericComboBoxPropsReturn { - disabledLabelTooltipTexts: { [label: string]: string }; - mappingConflictsTooltipInfo: { [label: string]: FieldConflictsInfo[] }; -} - -export interface DataViewField extends DataViewFieldBase { - esTypes?: string[]; -} diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.test.tsx deleted file mode 100644 index 801f8e2864d55..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.test.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mount } from 'enzyme'; - -import { AutocompleteFieldExistsComponent } from '.'; - -describe('AutocompleteFieldExistsComponent', () => { - test('it renders field disabled', () => { - const wrapper = mount(); - - expect( - wrapper - .find(`[data-test-subj="valuesAutocompleteComboBox existsComboxBox"] input`) - .prop('disabled') - ).toBeTruthy(); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.tsx deleted file mode 100644 index 592886905aaec..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui'; - -const NO_OPTIONS_FOR_EXIST: EuiComboBoxOptionOption[] = []; - -interface AutocompleteFieldExistsProps { - placeholder: string; - rowLabel?: string; - 'aria-label'?: string; -} - -export const AutocompleteFieldExistsComponent: React.FC = ({ - placeholder, - rowLabel, - 'aria-label': ariaLabel, -}): JSX.Element => ( - - - -); - -AutocompleteFieldExistsComponent.displayName = 'AutocompleteFieldExists'; diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx deleted file mode 100644 index b2d8dc0a70be9..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx +++ /dev/null @@ -1,270 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; -import { waitFor } from '@testing-library/react'; -import type { ListSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { getField } from '../fields/index.mock'; -import { AutocompleteFieldListsComponent } from '.'; -import { - getListResponseMock, - getFoundListsBySizeSchemaMock, - DATE_NOW, - IMMUTABLE, - VERSION, -} from '../list_schema/index.mock'; - -// TODO: Once these mocks are available, use them instead of hand mocking, https://github.com/elastic/kibana/issues/100715 -// const mockKibanaHttpService = coreMock.createStart().http; -// import { coreMock } from '../../../../../../../src/core/public/mocks'; -const mockKibanaHttpService = jest.fn(); -const mockShowValueListModal = jest.fn(); -const MockedShowValueListModal = (props: unknown) => { - mockShowValueListModal(props); - return <>; -}; -const mockStart = jest.fn(); -const mockKeywordList: ListSchema = { - ...getListResponseMock(), - id: 'keyword_list', - name: 'keyword list', - type: 'keyword', -}; -const mockResult = { ...getFoundListsBySizeSchemaMock() }; -mockResult.smallLists = [...mockResult.smallLists, mockKeywordList]; -mockResult.largeLists = []; -jest.mock('@kbn/securitysolution-list-hooks', () => { - const originalModule = jest.requireActual('@kbn/securitysolution-list-hooks'); - - return { - ...originalModule, - useFindListsBySize: () => ({ - error: undefined, - loading: false, - result: mockResult, - start: mockStart.mockReturnValue(mockResult), - }), - }; -}); - -describe('AutocompleteFieldListsComponent', () => { - test('it renders disabled if "isDisabled" is true', async () => { - const wrapper = mount( - - ); - - expect( - wrapper - .find(`[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] input`) - .prop('disabled') - ).toBeTruthy(); - }); - - test('it renders loading if "isLoading" is true', async () => { - const wrapper = mount( - - ); - - wrapper - .find(`[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] button`) - .at(0) - .simulate('click'); - expect( - wrapper - .find( - `EuiComboBoxOptionsList[data-test-subj="valuesAutocompleteComboBox listsComboxBox-optionsList"]` - ) - .prop('isLoading') - ).toBeTruthy(); - }); - - test('it allows user to clear values if "isClearable" is true', async () => { - const wrapper = mount( - - ); - expect( - wrapper - .find('EuiComboBox[data-test-subj="valuesAutocompleteComboBox listsComboxBox"]') - .prop('options') - ).toEqual([{ label: 'some name', disabled: false }]); - }); - - test('it correctly displays lists that match the selected "keyword" field esType', () => { - const wrapper = mount( - - ); - - wrapper.find('[data-test-subj="comboBoxToggleListButton"] button').simulate('click'); - - expect( - wrapper - .find('EuiComboBox[data-test-subj="valuesAutocompleteComboBox listsComboxBox"]') - .prop('options') - ).toEqual([{ label: 'keyword list', disabled: false }]); - }); - - test('it correctly displays lists that match the selected "ip" field esType', () => { - const wrapper = mount( - - ); - - wrapper.find('[data-test-subj="comboBoxToggleListButton"] button').simulate('click'); - - expect( - wrapper - .find('EuiComboBox[data-test-subj="valuesAutocompleteComboBox listsComboxBox"]') - .prop('options') - ).toEqual([{ label: 'some name', disabled: false }]); - }); - - test('it correctly displays selected list', async () => { - const wrapper = mount( - - ); - - expect( - wrapper - .find(`[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] input`) - .at(0) - .props().value - ).toEqual('some name'); - }); - - test('it invokes "onChange" when option selected', async () => { - const mockOnChange = jest.fn(); - const wrapper = mount( - - ); - - ( - wrapper.find(EuiComboBox).props() as unknown as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - } - ).onChange([{ label: 'some name', disabled: false }]); - - await waitFor(() => { - expect(mockOnChange).toHaveBeenCalledWith({ - '@timestamp': DATE_NOW, - _version: undefined, - created_at: DATE_NOW, - created_by: 'some user', - description: 'some description', - deserializer: undefined, - id: 'some-list-id', - immutable: IMMUTABLE, - meta: {}, - name: 'some name', - serializer: undefined, - tie_breaker_id: '6a76b69d-80df-4ab2-8c3e-85f466b06a0e', - type: 'ip', - updated_at: DATE_NOW, - updated_by: 'some user', - version: VERSION, - }); - }); - }); - - test('it render the value list modal', async () => { - mockShowValueListModal.mockReset(); - mount( - - ); - - expect(mockShowValueListModal).toHaveBeenCalledWith( - expect.objectContaining({ - children: 'Show value list', - listId: 'some-list-id', - shouldShowContentIfModalNotAvailable: false, - }) - ); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.tsx deleted file mode 100644 index c332dde356f29..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.tsx +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { ElementType, useCallback, useEffect, useMemo, useState } from 'react'; -import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow, EuiLink, EuiText } from '@elastic/eui'; -import type { ListSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { useFindListsBySize } from '@kbn/securitysolution-list-hooks'; -import { DataViewFieldBase } from '@kbn/es-query'; -import { getDocLinks } from '@kbn/doc-links'; - -import { filterFieldToList } from '../filter_field_to_list'; -import { getGenericComboBoxProps } from '../get_generic_combo_box_props'; - -// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 -// import { HttpStart } from '@kbn/core/public'; -type HttpStart = any; - -import * as i18n from '../translations'; - -const SINGLE_SELECTION = { asPlainText: true }; - -interface AutocompleteFieldListsProps { - httpService: HttpStart; - isClearable: boolean; - isDisabled: boolean; - isLoading: boolean; - onChange: (arg: ListSchema) => void; - placeholder: string; - rowLabel?: string; - selectedField: DataViewFieldBase | undefined; - selectedValue: string | undefined; - allowLargeValueLists?: boolean; - 'aria-label'?: string; - showValueListModal: ElementType; -} - -export interface AutocompleteListsData { - smallLists: ListSchema[]; - largeLists: ListSchema[]; -} - -export const AutocompleteFieldListsComponent: React.FC = ({ - httpService, - isClearable = false, - isDisabled = false, - isLoading = false, - onChange, - placeholder, - rowLabel, - selectedField, - selectedValue, - allowLargeValueLists = false, - 'aria-label': ariaLabel, - showValueListModal, -}): JSX.Element => { - const [error, setError] = useState(undefined); - const [listData, setListData] = useState({ - smallLists: [], - largeLists: [], - }); - const { loading, result, start } = useFindListsBySize(); - const getLabel = useCallback(({ name }: ListSchema) => name, []); - - const optionsMemo = useMemo( - () => filterFieldToList(listData, selectedField), - [listData, selectedField] - ); - const selectedOptionsMemo = useMemo(() => { - if (selectedValue != null) { - const combinedLists = [...listData.smallLists, ...listData.largeLists]; - const list = combinedLists.filter(({ id }) => id === selectedValue); - return list ?? []; - } else { - return []; - } - }, [selectedValue, listData]); - const { comboOptions, labels, selectedComboOptions } = useMemo( - () => - getGenericComboBoxProps({ - getLabel, - options: [...optionsMemo.smallLists, ...optionsMemo.largeLists], - selectedOptions: selectedOptionsMemo, - disabledOptions: allowLargeValueLists ? undefined : optionsMemo.largeLists, // Disable large lists if the rule type doesn't allow it - }), - [optionsMemo, selectedOptionsMemo, getLabel, allowLargeValueLists] - ); - - const handleValuesChange = useCallback( - (newOptions: EuiComboBoxOptionOption[]) => { - const combinedLists = [...optionsMemo.smallLists, ...optionsMemo.largeLists]; - const [newValue] = newOptions.map(({ label }) => combinedLists[labels.indexOf(label)]); - onChange(newValue ?? ''); - }, - [labels, optionsMemo, onChange] - ); - - const setIsTouchedValue = useCallback((): void => { - setError(selectedValue == null ? i18n.FIELD_REQUIRED_ERR : undefined); - }, [selectedValue]); - - useEffect(() => { - if (result != null) { - setListData(result); - } - }, [result]); - - useEffect(() => { - if (selectedField != null && httpService != null) { - start({ - http: httpService, - pageIndex: 1, - pageSize: 500, - }); - } - }, [selectedField, start, httpService]); - - const isLoadingState = useMemo((): boolean => isLoading || loading, [isLoading, loading]); - const ShowValueListModal = showValueListModal; - - const helpText = useMemo(() => { - return ( - <> - {selectedValue && ( - - {i18n.SHOW_VALUE_LIST_MODAL} - - )} - {!allowLargeValueLists && ( - - {i18n.LISTS_TOOLTIP_INFO}{' '} - - {i18n.SEE_DOCUMENTATION} - - - )} - - ); - }, [allowLargeValueLists, selectedValue, ShowValueListModal]); - return ( - - - - ); -}; - -AutocompleteFieldListsComponent.displayName = 'AutocompleteFieldList'; diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx deleted file mode 100644 index e83d79b180e90..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx +++ /dev/null @@ -1,631 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { ReactWrapper, mount } from 'enzyme'; -import { - EuiComboBox, - EuiComboBoxOptionOption, - EuiFormHelpText, - EuiSuperSelect, -} from '@elastic/eui'; -import { act, waitFor } from '@testing-library/react'; -import { AutocompleteFieldMatchComponent } from '.'; -import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; -import { fields, getField } from '../fields/index.mock'; -import { autocompleteStartMock } from '../autocomplete/index.mock'; - -jest.mock('../hooks/use_field_value_autocomplete'); -jest.mock('../translations', () => ({ - FIELD_SPACE_WARNING: 'Warning: there is a space', -})); -describe('AutocompleteFieldMatchComponent', () => { - let wrapper: ReactWrapper; - - const getValueSuggestionsMock = jest - .fn() - .mockResolvedValue([false, true, ['value 3', 'value 4'], jest.fn()]); - - const findEuiComboBox = () => - wrapper.find(EuiComboBox).props() as unknown as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - onSearchChange: (a: string) => void; - onCreateOption: (a: string) => void; - }; - - beforeEach(() => { - (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ - false, - true, - ['value 1', 'value 2'], - getValueSuggestionsMock, - ]); - }); - - afterEach(() => { - jest.clearAllMocks(); - wrapper.unmount(); - }); - - test('it renders row label if one passed in', () => { - wrapper = mount( - - ); - - expect( - wrapper.find('[data-test-subj="valuesAutocompleteMatchLabel"] label').at(0).text() - ).toEqual('Row Label'); - }); - - test('it renders disabled if "isDisabled" is true', () => { - wrapper = mount( - - ); - - expect( - wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').prop('disabled') - ).toBeTruthy(); - }); - - test('it renders loading if "isLoading" is true', () => { - wrapper = mount( - - ); - wrapper.find('[data-test-subj="valuesAutocompleteMatch"] button').at(0).simulate('click'); - expect( - wrapper - .find('EuiComboBoxOptionsList[data-test-subj="valuesAutocompleteMatch-optionsList"]') - .prop('isLoading') - ).toBeTruthy(); - }); - - test('it allows user to clear values if "isClearable" is true', () => { - wrapper = mount( - - ); - - expect(wrapper.find(`[data-test-subj="comboBoxClearButton"]`)).toBeTruthy(); - }); - - test('it correctly displays selected value', () => { - wrapper = mount( - - ); - - expect( - wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').at(0).props().value - ).toEqual('127.0.0.1'); - }); - - test('it invokes "onChange" when new value created', () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - findEuiComboBox().onCreateOption('127.0.0.1'); - - expect(mockOnChange).toHaveBeenCalledWith('127.0.0.1'); - }); - - test('it invokes "onChange" when new value selected', () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - findEuiComboBox().onChange([{ label: 'value 1' }]); - - expect(mockOnChange).toHaveBeenCalledWith('value 1'); - }); - - test('it invokes "onChange" with empty value (i.e. clears selection) when new value searched', () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - act(() => { - findEuiComboBox().onSearchChange('value 12'); - }); - - expect(mockOnChange).toHaveBeenCalledWith(''); - }); - - test('should show the warning helper text if the new value contains spaces when change', async () => { - (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ - false, - true, - [' value 1 ', 'value 2'], - getValueSuggestionsMock, - ]); - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - await waitFor(() => findEuiComboBox().onChange([{ label: ' value 1 ' }])); - wrapper.update(); - expect(mockOnChange).toHaveBeenCalledWith(' value 1 '); - - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeTruthy(); - }); - - test('it refreshes autocomplete with search query when new value searched', () => { - wrapper = mount( - - ); - act(() => { - findEuiComboBox().onSearchChange('value 1'); - }); - - expect(useFieldValueAutocomplete).toHaveBeenCalledWith({ - autocompleteService: autocompleteStartMock, - fieldValue: '', - indexPattern: { - fields, - id: '1234', - title: 'logstash-*', - }, - operatorType: 'match', - query: 'value 1', - selectedField: getField('machine.os.raw'), - }); - }); - - test('it refreshes autocomplete with search query when input field is cleared', () => { - wrapper = mount( - - ); - - act(() => { - findEuiComboBox().onSearchChange('value 1'); - }); - act(() => { - findEuiComboBox().onSearchChange(''); - }); - - // 1st call is initial render, 2nd call sets the search query: - expect(useFieldValueAutocomplete).toHaveBeenNthCalledWith(2, { - autocompleteService: autocompleteStartMock, - fieldValue: 'windows', - indexPattern: { fields, id: '1234', title: 'logstash-*' }, - operatorType: 'match', - query: 'value 1', - selectedField: getField('machine.os.raw'), - }); - // last call is the refresh when input field is cleared - expect(useFieldValueAutocomplete).toHaveBeenLastCalledWith({ - autocompleteService: autocompleteStartMock, - fieldValue: 'windows', - indexPattern: { fields, id: '1234', title: 'logstash-*' }, - operatorType: 'match', - query: '', - selectedField: getField('machine.os.raw'), - }); - }); - - test('should show the warning helper text if the new value contains spaces when searching a new query', () => { - wrapper = mount( - - ); - act(() => { - findEuiComboBox().onSearchChange(' value 1'); - }); - - wrapper.update(); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeTruthy(); - expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); - }); - - test('should show the warning helper text if selectedValue contains spaces when editing', () => { - wrapper = mount( - - ); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeTruthy(); - expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); - }); - - test('should not show the warning helper text if selectedValue is falsy', () => { - wrapper = mount( - - ); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeFalsy(); - }); - - describe('boolean type', () => { - const valueSuggestionsMock = jest.fn().mockResolvedValue([false, false, [], jest.fn()]); - - beforeEach(() => { - (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ - false, - false, - [], - valueSuggestionsMock, - ]); - }); - - test('it displays only two options - "true" or "false"', () => { - wrapper = mount( - - ); - expect( - wrapper.find('[data-test-subj="valuesAutocompleteMatchBoolean"]').exists() - ).toBeTruthy(); - expect( - wrapper.find('[data-test-subj="valuesAutocompleteMatchBoolean"]').at(0).prop('options') - ).toEqual([ - { - inputDisplay: 'true', - value: 'true', - }, - { - inputDisplay: 'false', - value: 'false', - }, - ]); - }); - - test('it invokes "onChange" with "true" when selected', () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - ( - wrapper.find(EuiSuperSelect).props() as unknown as { - onChange: (a: string) => void; - } - ).onChange('true'); - - expect(mockOnChange).toHaveBeenCalledWith('true'); - }); - - test('it invokes "onChange" with "false" when selected', () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - ( - wrapper.find(EuiSuperSelect).props() as unknown as { - onChange: (a: string) => void; - } - ).onChange('false'); - - expect(mockOnChange).toHaveBeenCalledWith('false'); - }); - }); - - describe('number type', () => { - const valueSuggestionsMock = jest.fn().mockResolvedValue([false, false, [], jest.fn()]); - - beforeEach(() => { - (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ - false, - false, - [], - valueSuggestionsMock, - ]); - }); - - test('it number input when field type is number', () => { - wrapper = mount( - - ); - - expect( - wrapper.find('[data-test-subj="valueAutocompleteFieldMatchNumber"]').exists() - ).toBeTruthy(); - }); - - test('it invokes "onChange" with numeric value when inputted', () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - wrapper - .find('[data-test-subj="valueAutocompleteFieldMatchNumber"] input') - .at(0) - .simulate('change', { target: { value: '8' } }); - - expect(mockOnChange).toHaveBeenCalledWith('8'); - }); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx deleted file mode 100644 index 5b627451db191..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx +++ /dev/null @@ -1,377 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { useCallback, useMemo, useState, useEffect } from 'react'; -import { - EuiSuperSelect, - EuiFormRow, - EuiFieldNumber, - EuiComboBoxOptionOption, - EuiComboBox, -} from '@elastic/eui'; -import { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; - -import { uniq } from 'lodash'; - -import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; - -// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 -// import { AutocompleteStart } from '../../../../../../../src/plugins/unified_search/public'; -type AutocompleteStart = any; - -import * as i18n from '../translations'; -import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; -import { - getGenericComboBoxProps, - GetGenericComboBoxPropsReturn, -} from '../get_generic_combo_box_props'; -import { paramIsValid } from '../param_is_valid'; -import { paramContainsSpace } from '../param_contains_space'; - -const BOOLEAN_OPTIONS = [ - { inputDisplay: 'true', value: 'true' }, - { inputDisplay: 'false', value: 'false' }, -]; - -const SINGLE_SELECTION = { asPlainText: true }; - -type Warning = string | React.ReactNode; - -interface AutocompleteFieldMatchProps { - placeholder: string; - selectedField: DataViewFieldBase | undefined; - selectedValue: string | undefined; - indexPattern: DataViewBase | undefined; - isLoading?: boolean; - isDisabled?: boolean; - isClearable?: boolean; - isRequired?: boolean; - fieldInputWidth?: number; - rowLabel?: string; - autocompleteService: AutocompleteStart; - onChange: (arg: string) => void; - onError?: (arg: boolean) => void; - onWarning?: (arg: boolean) => void; - warning?: Warning; - 'aria-label'?: string; -} - -export const AutocompleteFieldMatchComponent: React.FC = ({ - placeholder, - rowLabel, - selectedField, - selectedValue, - indexPattern, - isLoading = false, - isDisabled = false, - isClearable = false, - isRequired = false, - fieldInputWidth, - autocompleteService, - onChange, - onError, - onWarning, - warning, - 'aria-label': ariaLabel, -}): JSX.Element => { - const [searchQuery, setSearchQuery] = useState(''); - const [touched, setIsTouched] = useState(false); - const [error, setError] = useState(undefined); - const [showSpacesWarning, setShowSpacesWarning] = useState(false); - const [isLoadingSuggestions, isSuggestingValues, suggestions] = useFieldValueAutocomplete({ - autocompleteService, - fieldValue: selectedValue, - indexPattern, - operatorType: OperatorTypeEnum.MATCH, - query: searchQuery, - selectedField, - }); - const getLabel = useCallback((option: string): string => option, []); - - const optionsMemo = useMemo((): string[] => { - const valueAsStr = String(selectedValue); - return selectedValue != null && selectedValue.trim() !== '' - ? uniq([valueAsStr, ...suggestions]) - : suggestions; - }, [suggestions, selectedValue]); - - const selectedOptionsMemo = useMemo((): string[] => { - const valueAsStr = String(selectedValue); - return selectedValue ? [valueAsStr] : []; - }, [selectedValue]); - - const handleSpacesWarning = useCallback( - (param: string | undefined) => { - if (!param) return setShowSpacesWarning(false); - setShowSpacesWarning(!!paramContainsSpace(param)); - }, - [setShowSpacesWarning] - ); - - const handleError = useCallback( - (err: string | undefined): void => { - setError((existingErr): string | undefined => { - const oldErr = existingErr != null; - const newErr = err != null; - if (oldErr !== newErr && onError != null) { - onError(newErr); - } - - return err; - }); - }, - [setError, onError] - ); - - const handleWarning = useCallback( - (warn: Warning | undefined): void => { - if (onWarning) { - onWarning(warn !== undefined); - } - }, - [onWarning] - ); - - const { comboOptions, labels, selectedComboOptions } = useMemo( - (): GetGenericComboBoxPropsReturn => - getGenericComboBoxProps({ - getLabel, - options: optionsMemo, - selectedOptions: selectedOptionsMemo, - }), - [optionsMemo, selectedOptionsMemo, getLabel] - ); - - const handleValuesChange = useCallback( - (newOptions: EuiComboBoxOptionOption[]): void => { - const [newValue] = newOptions.map(({ label }) => optionsMemo[labels.indexOf(label)]); - - handleSpacesWarning(newValue); - handleError(undefined); - handleWarning(undefined); - onChange(newValue ?? ''); - }, - [handleError, handleWarning, handleSpacesWarning, labels, onChange, optionsMemo] - ); - - const handleSearchChange = useCallback( - (searchVal: string): void => { - if (searchVal !== '' && selectedField != null) { - const err = paramIsValid(searchVal, selectedField, isRequired, touched); - handleError(err); - handleWarning(warning); - - if (!err) handleSpacesWarning(searchVal); - } - - if (searchVal) { - // Clear selected option when user types to allow user to modify value without {backspace} - onChange(''); - } - - // Update search query unconditionally to show correct suggestions even when input is cleared - setSearchQuery(searchVal); - }, - [ - selectedField, - onChange, - isRequired, - touched, - handleError, - handleWarning, - warning, - handleSpacesWarning, - ] - ); - - const handleCreateOption = useCallback( - (option: string): boolean | undefined => { - const err = paramIsValid(option, selectedField, isRequired, touched); - handleError(err); - handleWarning(warning); - - if (err != null) { - // Explicitly reject the user's input - setShowSpacesWarning(false); - return false; - } - - handleSpacesWarning(option); - onChange(option); - return undefined; - }, - [ - isRequired, - onChange, - selectedField, - touched, - handleError, - handleSpacesWarning, - handleWarning, - warning, - ] - ); - - const handleNonComboBoxInputChange = useCallback( - (event: React.ChangeEvent): void => { - const newValue = event.target.value; - onChange(newValue); - }, - [onChange] - ); - - const handleBooleanInputChange = useCallback( - (newOption: string): void => { - onChange(newOption); - }, - [onChange] - ); - - const setIsTouchedValue = useCallback((): void => { - setIsTouched(true); - - const err = paramIsValid(selectedValue, selectedField, isRequired, true); - handleError(err); - handleWarning(warning); - }, [setIsTouched, handleError, selectedValue, selectedField, isRequired, warning, handleWarning]); - - const inputPlaceholder = useMemo((): string => { - if (isLoading || isLoadingSuggestions) { - return i18n.LOADING; - } else if (selectedField == null) { - return i18n.SELECT_FIELD_FIRST; - } else { - return placeholder; - } - }, [isLoading, selectedField, isLoadingSuggestions, placeholder]); - - const isLoadingState = useMemo( - (): boolean => isLoading || isLoadingSuggestions, - [isLoading, isLoadingSuggestions] - ); - - useEffect((): void => { - setError(undefined); - if (onError != null) onError(false); - - handleSpacesWarning(selectedValue); - // Looks like selectedField return new object every time when we for example add "and" entry - // that's why we need to check for name and type here - // Probably we should use some kind of memoization on parent components for entries - }, [selectedField?.name, selectedField?.type, selectedValue, handleSpacesWarning, onError]); - - const defaultInput = useMemo((): JSX.Element => { - return ( - - - - ); - }, [ - rowLabel, - error, - selectedField, - showSpacesWarning, - inputPlaceholder, - isDisabled, - isLoadingState, - isClearable, - comboOptions, - selectedComboOptions, - handleValuesChange, - handleSearchChange, - handleCreateOption, - setIsTouchedValue, - warning, - fieldInputWidth, - ariaLabel, - ]); - - if (!isSuggestingValues && selectedField != null) { - switch (selectedField.type) { - case 'number': - return ( - - 0 - ? parseFloat(selectedValue) - : selectedValue ?? '' - } - onChange={handleNonComboBoxInputChange} - data-test-subj="valueAutocompleteFieldMatchNumber" - style={fieldInputWidth ? { width: `${fieldInputWidth}px` } : {}} - aria-label={ariaLabel} - fullWidth - /> - - ); - case 'boolean': - return ( - - - - ); - default: - return defaultInput; - } - } else { - return defaultInput; - } -}; - -AutocompleteFieldMatchComponent.displayName = 'AutocompleteFieldMatch'; diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.test.tsx deleted file mode 100644 index 0b73a57814aaf..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.test.tsx +++ /dev/null @@ -1,400 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { ReactWrapper, mount } from 'enzyme'; -import { EuiComboBox, EuiComboBoxOptionOption, EuiFormHelpText } from '@elastic/eui'; -import { act, waitFor } from '@testing-library/react'; - -import { AutocompleteFieldMatchAnyComponent } from '.'; -import { getField, fields } from '../fields/index.mock'; -import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; -import { autocompleteStartMock } from '../autocomplete/index.mock'; - -jest.mock('../hooks/use_field_value_autocomplete', () => { - const actual = jest.requireActual('../hooks/use_field_value_autocomplete'); - return { - ...actual, - useFieldValueAutocomplete: jest.fn(), - }; -}); -jest.mock('../translations', () => ({ - FIELD_SPACE_WARNING: 'Warning: there is a space', -})); - -describe('AutocompleteFieldMatchAnyComponent', () => { - let wrapper: ReactWrapper; - const getValueSuggestionsMock = jest - .fn() - .mockResolvedValue([false, true, ['value 3', 'value 4'], jest.fn()]); - - beforeEach(() => { - (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ - false, - true, - ['value 1', 'value 2'], - getValueSuggestionsMock, - ]); - }); - - afterEach(() => { - jest.clearAllMocks(); - wrapper.unmount(); - }); - - test('it renders disabled if "isDisabled" is true', () => { - wrapper = mount( - - ); - - expect( - wrapper.find(`[data-test-subj="valuesAutocompleteMatchAny"] input`).prop('disabled') - ).toBeTruthy(); - }); - - test('it renders loading if "isLoading" is true', () => { - wrapper = mount( - - ); - wrapper.find(`[data-test-subj="valuesAutocompleteMatchAny"] button`).at(0).simulate('click'); - expect( - wrapper - .find(`EuiComboBoxOptionsList[data-test-subj="valuesAutocompleteMatchAny-optionsList"]`) - .prop('isLoading') - ).toBeTruthy(); - }); - - test('it allows user to clear values if "isClearable" is true', () => { - wrapper = mount( - - ); - - expect(wrapper.find(`[data-test-subj="comboBoxClearButton"]`)).toBeTruthy(); - }); - - test('it correctly displays selected value', () => { - wrapper = mount( - - ); - - expect( - wrapper.find(`[data-test-subj="valuesAutocompleteMatchAny"] EuiComboBoxPill`).at(0).text() - ).toEqual('127.0.0.1'); - }); - - test('it invokes "onChange" when new value created', async () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - ( - wrapper.find(EuiComboBox).props() as unknown as { - onCreateOption: (a: string) => void; - } - ).onCreateOption('127.0.0.1'); - - expect(mockOnChange).toHaveBeenCalledWith(['127.0.0.1']); - }); - - test('it invokes "onChange" when new value selected', async () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - ( - wrapper.find(EuiComboBox).props() as unknown as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - } - ).onChange([{ label: 'value 1' }]); - - expect(mockOnChange).toHaveBeenCalledWith(['value 1']); - }); - - test('it refreshes autocomplete with search query when new value searched', () => { - wrapper = mount( - - ); - act(() => { - ( - wrapper.find(EuiComboBox).props() as unknown as { - onSearchChange: (a: string) => void; - } - ).onSearchChange('value 1'); - }); - expect(useFieldValueAutocomplete).toHaveBeenCalledWith({ - autocompleteService: autocompleteStartMock, - fieldValue: [], - indexPattern: { - fields, - id: '1234', - title: 'logstash-*', - }, - operatorType: 'match_any', - query: 'value 1', - selectedField: getField('machine.os.raw'), - }); - }); - test('should show the warning helper text if the new value contains spaces when change', async () => { - (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ - false, - true, - [' value 1 ', 'value 2'], - getValueSuggestionsMock, - ]); - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - await waitFor(() => - ( - wrapper.find(EuiComboBox).props() as unknown as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - } - ).onChange([{ label: ' value 1 ' }]) - ); - wrapper.update(); - expect(mockOnChange).toHaveBeenCalledWith([' value 1 ']); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeTruthy(); - }); - test('should show the warning helper text if the new value contains spaces when searching a new query', () => { - wrapper = mount( - - ); - act(() => { - ( - wrapper.find(EuiComboBox).props() as unknown as { - onSearchChange: (a: string) => void; - } - ).onSearchChange(' value 1'); - }); - - wrapper.update(); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeTruthy(); - expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); - }); - test('should show the warning helper text if selectedValue contains spaces when editing', () => { - wrapper = mount( - - ); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeTruthy(); - expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); - }); - test('should not show the warning helper text if selectedValue is falsy', () => { - wrapper = mount( - - ); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeFalsy(); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.tsx deleted file mode 100644 index 761712797c5e1..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.tsx +++ /dev/null @@ -1,253 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui'; -import { uniq } from 'lodash'; -import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; - -// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 -// import { AutocompleteStart } from '../../../../../../../src/plugins/unified_search/public'; -type AutocompleteStart = any; - -import * as i18n from '../translations'; -import { - getGenericComboBoxProps, - GetGenericComboBoxPropsReturn, -} from '../get_generic_combo_box_props'; -import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; -import { paramIsValid } from '../param_is_valid'; -import { paramContainsSpace } from '../param_contains_space'; - -interface AutocompleteFieldMatchAnyProps { - placeholder: string; - selectedField: DataViewFieldBase | undefined; - selectedValue: string[]; - indexPattern: DataViewBase | undefined; - isLoading: boolean; - isDisabled: boolean; - isClearable: boolean; - isRequired?: boolean; - rowLabel?: string; - autocompleteService: AutocompleteStart; - onChange: (arg: string[]) => void; - onError?: (arg: boolean) => void; - 'aria-label'?: string; -} - -export const AutocompleteFieldMatchAnyComponent: React.FC = ({ - placeholder, - rowLabel, - selectedField, - selectedValue, - indexPattern, - isLoading, - isDisabled = false, - isClearable = false, - isRequired = false, - onChange, - onError, - autocompleteService, - 'aria-label': ariaLabel, -}): JSX.Element => { - const [searchQuery, setSearchQuery] = useState(''); - const [touched, setIsTouched] = useState(false); - const [error, setError] = useState(undefined); - const [showSpacesWarning, setShowSpacesWarning] = useState(false); - const [isLoadingSuggestions, isSuggestingValues, suggestions] = useFieldValueAutocomplete({ - autocompleteService, - fieldValue: selectedValue, - indexPattern, - operatorType: OperatorTypeEnum.MATCH_ANY, - query: searchQuery, - selectedField, - }); - const getLabel = useCallback((option: string): string => option, []); - const optionsMemo = useMemo( - (): string[] => (selectedValue ? uniq([...selectedValue, ...suggestions]) : suggestions), - [suggestions, selectedValue] - ); - const { comboOptions, labels, selectedComboOptions } = useMemo( - (): GetGenericComboBoxPropsReturn => - getGenericComboBoxProps({ - getLabel, - options: optionsMemo, - selectedOptions: selectedValue, - }), - [optionsMemo, selectedValue, getLabel] - ); - const handleSpacesWarning = useCallback( - (params: string[]) => - setShowSpacesWarning(!!params.find((param: string) => paramContainsSpace(param))), - [setShowSpacesWarning] - ); - const handleError = useCallback( - (err: string | undefined): void => { - setError((existingErr): string | undefined => { - const oldErr = existingErr != null; - const newErr = err != null; - if (oldErr !== newErr && onError != null) { - onError(newErr); - } - - return err; - }); - }, - [setError, onError] - ); - - const handleValuesChange = useCallback( - (newOptions: EuiComboBoxOptionOption[]): void => { - const newValues: string[] = newOptions.map(({ label }) => optionsMemo[labels.indexOf(label)]); - handleError(undefined); - handleSpacesWarning(newValues); - onChange(newValues); - }, - [handleError, handleSpacesWarning, labels, onChange, optionsMemo] - ); - - const handleSearchChange = useCallback( - (searchVal: string) => { - if (searchVal === '') { - handleError(undefined); - } - - if (searchVal !== '' && selectedField != null) { - const err = paramIsValid(searchVal, selectedField, isRequired, touched); - handleError(err); - - if (!err) handleSpacesWarning([searchVal]); - - setSearchQuery(searchVal); - } - }, - [handleError, handleSpacesWarning, isRequired, selectedField, touched] - ); - - const handleCreateOption = useCallback( - (option: string): boolean => { - const err = paramIsValid(option, selectedField, isRequired, touched); - handleError(err); - - if (err != null) { - // Explicitly reject the user's input - setShowSpacesWarning(false); - return false; - } - - onChange([...(selectedValue || []), option]); - handleSpacesWarning([option]); - return true; - }, - [handleError, handleSpacesWarning, isRequired, onChange, selectedField, selectedValue, touched] - ); - - const setIsTouchedValue = useCallback((): void => { - handleError(selectedComboOptions.length === 0 ? i18n.FIELD_REQUIRED_ERR : undefined); - setIsTouched(true); - }, [setIsTouched, handleError, selectedComboOptions]); - - const inputPlaceholder = useMemo( - (): string => (isLoading || isLoadingSuggestions ? i18n.LOADING : placeholder), - [isLoading, isLoadingSuggestions, placeholder] - ); - - const isLoadingState = useMemo( - (): boolean => isLoading || isLoadingSuggestions, - [isLoading, isLoadingSuggestions] - ); - useEffect((): void => { - handleSpacesWarning(selectedValue); - }, [selectedField, selectedValue, handleSpacesWarning]); - - const defaultInput = useMemo((): JSX.Element => { - return ( - - - - ); - }, [ - rowLabel, - error, - selectedField, - showSpacesWarning, - inputPlaceholder, - isLoadingState, - isClearable, - isDisabled, - comboOptions, - selectedComboOptions, - handleValuesChange, - handleSearchChange, - handleCreateOption, - setIsTouchedValue, - ariaLabel, - ]); - - if (!isSuggestingValues && selectedField != null) { - switch (selectedField.type) { - case 'number': - return ( - - - - ); - default: - return defaultInput; - } - } - - return defaultInput; -}; - -AutocompleteFieldMatchAnyComponent.displayName = 'AutocompleteFieldMatchAny'; diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx deleted file mode 100644 index 2840e428a69e2..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx +++ /dev/null @@ -1,516 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { ReactWrapper, mount } from 'enzyme'; -import { EuiComboBox, EuiComboBoxOptionOption, EuiFormHelpText } from '@elastic/eui'; -import { act, waitFor } from '@testing-library/react'; -import { AutocompleteFieldWildcardComponent } from '.'; -import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; -import { fields, getField } from '../fields/index.mock'; -import { autocompleteStartMock } from '../autocomplete/index.mock'; -import { WILDCARD_WARNING, FILEPATH_WARNING } from '@kbn/securitysolution-utils'; - -jest.mock('../hooks/use_field_value_autocomplete'); -jest.mock('../translations', () => ({ - FIELD_SPACE_WARNING: 'Warning: there is a space', -})); -describe('AutocompleteFieldWildcardComponent', () => { - let wrapper: ReactWrapper; - - const getValueSuggestionsMock = jest - .fn() - .mockResolvedValue([false, true, ['value 3', 'value 4'], jest.fn()]); - - beforeEach(() => { - (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ - false, - true, - ['value 1', 'value 2'], - getValueSuggestionsMock, - ]); - }); - - afterEach(() => { - jest.clearAllMocks(); - wrapper.unmount(); - }); - - test('it renders row label if one passed in', () => { - wrapper = mount( - - ); - - expect( - wrapper.find('[data-test-subj="valuesAutocompleteWildcardLabel"] label').at(0).text() - ).toEqual('Row Label'); - }); - - test('it renders disabled if "isDisabled" is true', () => { - wrapper = mount( - - ); - - expect( - wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] input').prop('disabled') - ).toBeTruthy(); - }); - - test('it renders loading if "isLoading" is true', () => { - wrapper = mount( - - ); - wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] button').at(0).simulate('click'); - expect( - wrapper - .find('EuiComboBoxOptionsList[data-test-subj="valuesAutocompleteWildcard-optionsList"]') - .prop('isLoading') - ).toBeTruthy(); - }); - - test('it allows user to clear values if "isClearable" is true', () => { - wrapper = mount( - - ); - - expect(wrapper.find(`[data-test-subj="comboBoxClearButton"]`)).toBeTruthy(); - }); - - test('it correctly displays selected value', () => { - wrapper = mount( - - ); - - expect( - wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] input').at(0).props().value - ).toEqual('/opt/*/app.dmg'); - }); - - test('it invokes "onChange" when new value created', async () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - ( - wrapper.find(EuiComboBox).props() as unknown as { - onCreateOption: (a: string) => void; - } - ).onCreateOption('/opt/*/app.dmg'); - - expect(mockOnChange).toHaveBeenCalledWith('/opt/*/app.dmg'); - }); - - test('it invokes "onChange" when new value selected', async () => { - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - ( - wrapper.find(EuiComboBox).props() as unknown as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - } - ).onChange([{ label: 'value 1' }]); - - expect(mockOnChange).toHaveBeenCalledWith('value 1'); - }); - - test('it refreshes autocomplete with search query when new value searched', () => { - wrapper = mount( - - ); - act(() => { - ( - wrapper.find(EuiComboBox).props() as unknown as { - onSearchChange: (a: string) => void; - } - ).onSearchChange('A:\\Some Folder\\inc*.exe'); - }); - - expect(useFieldValueAutocomplete).toHaveBeenCalledWith({ - autocompleteService: autocompleteStartMock, - fieldValue: '', - indexPattern: { - fields, - id: '1234', - title: 'logs-endpoint.events.*', - }, - operatorType: 'wildcard', - query: 'A:\\Some Folder\\inc*.exe', - selectedField: getField('file.path.text'), - }); - }); - - test('it does not invoke "onWarning" when no warning exists', () => { - const mockOnWarning = jest.fn(); - wrapper = mount( - - ); - - act(() => { - ( - wrapper.find(EuiComboBox).props() as unknown as { - onBlur: () => void; - } - ).onBlur(); - }); - - expect(mockOnWarning).not.toHaveBeenCalledWith(true); - }); - - test('it invokes "onWarning" when warning exists', () => { - const mockOnWarning = jest.fn(); - wrapper = mount( - - ); - - act(() => { - ( - wrapper.find(EuiComboBox).props() as unknown as { - onBlur: () => void; - } - ).onBlur(); - }); - - expect(mockOnWarning).toHaveBeenCalledWith(true); - expect( - wrapper - .find('[data-test-subj="valuesAutocompleteWildcardLabel"] div.euiFormHelpText') - .at(0) - .text() - ).toEqual(FILEPATH_WARNING); - }); - - test('it invokes "onWarning" when warning exists and is wildcard warning', () => { - const mockOnWarning = jest.fn(); - wrapper = mount( - - ); - - act(() => { - ( - wrapper.find(EuiComboBox).props() as unknown as { - onBlur: () => void; - } - ).onBlur(); - }); - - expect(mockOnWarning).toHaveBeenCalledWith(true); - const helpText = wrapper - .find('[data-test-subj="valuesAutocompleteWildcardLabel"] div.euiFormHelpText') - .at(0); - expect(helpText.text()).toEqual(WILDCARD_WARNING); - expect(helpText.find('.euiToolTipAnchor')).toBeTruthy(); - }); - test('should show the warning helper text if the new value contains spaces when change', async () => { - (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ - false, - true, - [' value 1 ', 'value 2'], - getValueSuggestionsMock, - ]); - const mockOnChange = jest.fn(); - wrapper = mount( - - ); - - await waitFor(() => - ( - wrapper.find(EuiComboBox).props() as unknown as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - } - ).onChange([{ label: ' value 1 ' }]) - ); - wrapper.update(); - expect(mockOnChange).toHaveBeenCalledWith(' value 1 '); - - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeTruthy(); - }); - test('should show the warning helper text if the new value contains spaces when searching a new query', () => { - wrapper = mount( - - ); - act(() => { - ( - wrapper.find(EuiComboBox).props() as unknown as { - onSearchChange: (a: string) => void; - } - ).onSearchChange(' value 1'); - }); - - wrapper.update(); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeTruthy(); - expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); - }); - test('should show the warning helper text if selectedValue contains spaces when editing', () => { - wrapper = mount( - - ); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeTruthy(); - expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); - }); - test('should not show the warning helper text if selectedValue is falsy', () => { - wrapper = mount( - - ); - const euiFormHelptext = wrapper.find(EuiFormHelpText); - expect(euiFormHelptext.length).toBeFalsy(); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.tsx deleted file mode 100644 index 5a55b3399a6af..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.tsx +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { useCallback, useMemo, useState, useEffect, memo } from 'react'; -import { EuiFormRow, EuiComboBoxOptionOption, EuiComboBox } from '@elastic/eui'; -import { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; - -import { uniq } from 'lodash'; - -import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; - -// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 -// import { AutocompleteStart } from '../../../../../../../src/plugins/unified_search/public'; -type AutocompleteStart = any; - -import * as i18n from '../translations'; -import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; -import { - getGenericComboBoxProps, - GetGenericComboBoxPropsReturn, -} from '../get_generic_combo_box_props'; -import { paramIsValid } from '../param_is_valid'; -import { paramContainsSpace } from '../param_contains_space'; - -const SINGLE_SELECTION = { asPlainText: true }; - -type Warning = string | React.ReactNode; -interface AutocompleteFieldWildcardProps { - placeholder: string; - selectedField: DataViewFieldBase | undefined; - selectedValue: string | undefined; - indexPattern: DataViewBase | undefined; - isLoading: boolean; - isDisabled?: boolean; - isClearable?: boolean; - isRequired?: boolean; - fieldInputWidth?: number; - rowLabel?: string; - autocompleteService: AutocompleteStart; - onChange: (arg: string) => void; - onError: (arg: boolean) => void; - onWarning: (arg: boolean) => void; - warning?: Warning; - 'aria-label'?: string; -} - -export const AutocompleteFieldWildcardComponent: React.FC = memo( - ({ - autocompleteService, - placeholder, - rowLabel, - selectedField, - selectedValue, - indexPattern, - isLoading, - isDisabled = false, - isClearable = false, - isRequired = false, - fieldInputWidth, - onChange, - onError, - onWarning, - warning, - 'aria-label': ariaLabel, - }): JSX.Element => { - const [searchQuery, setSearchQuery] = useState(''); - const [touched, setIsTouched] = useState(false); - const [error, setError] = useState(undefined); - const [showSpacesWarning, setShowSpacesWarning] = useState(false); - const [isLoadingSuggestions, , suggestions] = useFieldValueAutocomplete({ - autocompleteService, - fieldValue: selectedValue, - indexPattern, - operatorType: OperatorTypeEnum.WILDCARD, - query: searchQuery, - selectedField, - }); - const getLabel = useCallback((option: string): string => option, []); - const optionsMemo = useMemo((): string[] => { - const valueAsStr = String(selectedValue); - return selectedValue != null && selectedValue.trim() !== '' - ? uniq([valueAsStr, ...suggestions]) - : suggestions; - }, [suggestions, selectedValue]); - const selectedOptionsMemo = useMemo((): string[] => { - const valueAsStr = String(selectedValue); - return selectedValue ? [valueAsStr] : []; - }, [selectedValue]); - - const handleSpacesWarning = useCallback( - (param: string | undefined) => { - if (!param) return setShowSpacesWarning(false); - setShowSpacesWarning(!!paramContainsSpace(param)); - }, - [setShowSpacesWarning] - ); - const handleError = useCallback( - (err: string | undefined): void => { - setError((existingErr): string | undefined => { - const oldErr = existingErr != null; - const newErr = err != null; - if (oldErr !== newErr && onError != null) { - onError(newErr); - } - - return err; - }); - }, - [setError, onError] - ); - - const handleWarning = useCallback( - (warn: Warning | undefined): void => { - onWarning(warn !== undefined); - }, - [onWarning] - ); - - const { comboOptions, labels, selectedComboOptions } = useMemo( - (): GetGenericComboBoxPropsReturn => - getGenericComboBoxProps({ - getLabel, - options: optionsMemo, - selectedOptions: selectedOptionsMemo, - }), - [optionsMemo, selectedOptionsMemo, getLabel] - ); - - const handleValuesChange = useCallback( - (newOptions: EuiComboBoxOptionOption[]): void => { - const [newValue] = newOptions.map(({ label }) => optionsMemo[labels.indexOf(label)]); - handleError(undefined); - handleSpacesWarning(newValue); - setShowSpacesWarning(false); - - onChange(newValue ?? ''); - }, - [handleError, handleSpacesWarning, labels, onChange, optionsMemo] - ); - - const handleSearchChange = useCallback( - (searchVal: string): void => { - if (searchVal.trim() !== '' && selectedField != null) { - const err = paramIsValid(searchVal, selectedField, isRequired, touched); - handleError(err); - handleWarning(warning); - if (!err) handleSpacesWarning(searchVal); - - setSearchQuery(searchVal); - } - }, - [handleError, handleSpacesWarning, isRequired, selectedField, touched, warning, handleWarning] - ); - - const handleCreateOption = useCallback( - (option: string): boolean | undefined => { - const err = paramIsValid(option, selectedField, isRequired, touched); - handleError(err); - handleWarning(warning); - - if (err != null) { - // Explicitly reject the user's input - setShowSpacesWarning(false); - return false; - } - - handleSpacesWarning(option); - onChange(option); - return undefined; - }, - [ - isRequired, - handleSpacesWarning, - onChange, - selectedField, - touched, - handleError, - handleWarning, - warning, - ] - ); - - const setIsTouchedValue = useCallback((): void => { - setIsTouched(true); - - const err = paramIsValid(selectedValue, selectedField, isRequired, true); - handleError(err); - handleWarning(warning); - }, [ - setIsTouched, - handleError, - selectedValue, - selectedField, - isRequired, - handleWarning, - warning, - ]); - - const inputPlaceholder = useMemo((): string => { - if (isLoading || isLoadingSuggestions) { - return i18n.LOADING; - } else if (selectedField == null) { - return i18n.SELECT_FIELD_FIRST; - } else { - return placeholder; - } - }, [isLoading, selectedField, isLoadingSuggestions, placeholder]); - - const isLoadingState = useMemo( - (): boolean => isLoading || isLoadingSuggestions, - [isLoading, isLoadingSuggestions] - ); - - useEffect((): void => { - setError(undefined); - if (onError != null) { - onError(false); - } - handleSpacesWarning(selectedValue); - - onWarning(false); - }, [selectedField, selectedValue, onError, onWarning, handleSpacesWarning]); - - const defaultInput = useMemo((): JSX.Element => { - return ( - - - - ); - }, [ - rowLabel, - error, - warning, - showSpacesWarning, - selectedField, - inputPlaceholder, - isDisabled, - isLoadingState, - isClearable, - comboOptions, - selectedComboOptions, - handleValuesChange, - handleSearchChange, - handleCreateOption, - setIsTouchedValue, - fieldInputWidth, - ariaLabel, - ]); - - return defaultInput; - } -); - -AutocompleteFieldWildcardComponent.displayName = 'AutocompleteFieldWildcard'; diff --git a/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts b/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts deleted file mode 100644 index dcb719ccdb56c..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts +++ /dev/null @@ -1,323 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DataViewFieldBase } from '@kbn/es-query'; - -// Copied from "src/plugins/data/common/index_patterns/fields/fields.mocks.ts" but with the types changed to "DataViewFieldBase" since that type is compatible. -// TODO: This should move out once those mocks are directly useable or in their own package, https://github.com/elastic/kibana/issues/100715 - -export const fields: DataViewFieldBase[] = [ - { - name: 'bytes', - type: 'number', - esTypes: ['long'], - count: 10, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'ssl', - type: 'boolean', - esTypes: ['boolean'], - count: 20, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: '@timestamp', - type: 'date', - esTypes: ['date'], - count: 30, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'time', - type: 'date', - esTypes: ['date'], - count: 30, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: '@tags', - type: 'string', - esTypes: ['keyword'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'utc_time', - type: 'date', - esTypes: ['date'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'phpmemory', - type: 'number', - esTypes: ['integer'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'ip', - type: 'ip', - esTypes: ['ip'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'request_body', - type: 'attachment', - esTypes: ['attachment'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'point', - type: 'geo_point', - esTypes: ['geo_point'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'area', - type: 'geo_shape', - esTypes: ['geo_shape'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'hashed', - type: 'murmur3', - esTypes: ['murmur3'], - count: 0, - scripted: false, - searchable: true, - aggregatable: false, - readFromDocValues: false, - }, - { - name: 'geo.coordinates', - type: 'geo_point', - esTypes: ['geo_point'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'extension', - type: 'string', - esTypes: ['keyword'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'machine.os', - type: 'string', - esTypes: ['text'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: false, - }, - { - name: 'machine.os.raw', - type: 'string', - esTypes: ['keyword'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - subType: { multi: { parent: 'machine.os' } }, - }, - { - name: 'geo.src', - type: 'string', - esTypes: ['keyword'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: '_id', - type: 'string', - esTypes: ['_id'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: false, - }, - { - name: '_type', - type: 'string', - esTypes: ['_type'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: false, - }, - { - name: '_source', - type: '_source', - esTypes: ['_source'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: false, - }, - { - name: 'non-filterable', - type: 'string', - esTypes: ['text'], - count: 0, - scripted: false, - searchable: false, - aggregatable: true, - readFromDocValues: false, - }, - { - name: 'non-sortable', - type: 'string', - esTypes: ['text'], - count: 0, - scripted: false, - searchable: false, - aggregatable: false, - readFromDocValues: false, - }, - { - name: 'custom_user_field', - type: 'conflict', - esTypes: ['long', 'text'], - count: 0, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - }, - { - name: 'script string', - type: 'string', - count: 0, - scripted: true, - script: "'i am a string'", - lang: 'expression', - searchable: true, - aggregatable: true, - readFromDocValues: false, - }, - { - name: 'script number', - type: 'number', - count: 0, - scripted: true, - script: '1234', - lang: 'expression', - searchable: true, - aggregatable: true, - readFromDocValues: false, - }, - { - name: 'script date', - type: 'date', - count: 0, - scripted: true, - script: '1234', - lang: 'painless', - searchable: true, - aggregatable: true, - readFromDocValues: false, - }, - { - name: 'script murmur3', - type: 'murmur3', - count: 0, - scripted: true, - script: '1234', - lang: 'expression', - searchable: true, - aggregatable: true, - readFromDocValues: false, - }, - { - name: 'nestedField.child', - type: 'string', - esTypes: ['text'], - count: 0, - scripted: false, - searchable: true, - aggregatable: false, - readFromDocValues: false, - subType: { nested: { path: 'nestedField' } }, - }, - { - name: 'nestedField.nestedChild.doublyNestedChild', - type: 'string', - esTypes: ['text'], - count: 0, - scripted: false, - searchable: true, - aggregatable: false, - readFromDocValues: false, - subType: { nested: { path: 'nestedField.nestedChild' } }, - }, - { - name: 'file.path.text', - type: 'string', - esTypes: ['text'], - searchable: true, - aggregatable: false, - subType: { multi: { parent: 'file.path' } }, - }, -] as unknown as DataViewFieldBase[]; - -export const getField = (name: string) => fields.find((field) => field.name === name); diff --git a/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.test.ts b/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.test.ts deleted file mode 100644 index be0710bfd1bab..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { filterFieldToList } from '.'; - -import { getListResponseMock } from '../list_schema/index.mock'; -import { DataViewFieldBase } from '@kbn/es-query'; -import { AutocompleteListsData } from '../field_value_lists'; - -const emptyListData: AutocompleteListsData = { smallLists: [], largeLists: [] }; - -describe('#filterFieldToList', () => { - test('it returns empty list data object if given a undefined for field', () => { - const filter = filterFieldToList(emptyListData, undefined); - expect(filter).toEqual(emptyListData); - }); - - test('it returns empty list data object if filed does not contain esTypes', () => { - const field: DataViewFieldBase = { - name: 'some-name', - type: 'some-type', - }; - const filter = filterFieldToList(emptyListData, field); - expect(filter).toEqual(emptyListData); - }); - - test('it returns filtered lists of ip_range -> ip', () => { - const field: DataViewFieldBase & { esTypes: string[] } = { - esTypes: ['ip'], - name: 'some-name', - type: 'ip', - }; - const listData: AutocompleteListsData = { - smallLists: [{ ...getListResponseMock(), type: 'ip_range' }], - largeLists: [], - }; - const filter = filterFieldToList(listData, field); - const expected = listData; - expect(filter).toEqual(expected); - }); - - test('it returns filtered lists of ip -> ip', () => { - const field: DataViewFieldBase & { esTypes: string[] } = { - esTypes: ['ip'], - name: 'some-name', - type: 'ip', - }; - const listData: AutocompleteListsData = { - smallLists: [{ ...getListResponseMock(), type: 'ip' }], - largeLists: [], - }; - const filter = filterFieldToList(listData, field); - const expected = listData; - expect(filter).toEqual(expected); - }); - - test('it returns filtered lists of keyword -> keyword', () => { - const field: DataViewFieldBase & { esTypes: string[] } = { - esTypes: ['keyword'], - name: 'some-name', - type: 'keyword', - }; - const listData: AutocompleteListsData = { - smallLists: [{ ...getListResponseMock(), type: 'keyword' }], - largeLists: [], - }; - const filter = filterFieldToList(listData, field); - const expected = listData; - expect(filter).toEqual(expected); - }); - - test('it returns filtered lists of text -> text', () => { - const field: DataViewFieldBase & { esTypes: string[] } = { - esTypes: ['text'], - name: 'some-name', - type: 'text', - }; - const listData: AutocompleteListsData = { - smallLists: [{ ...getListResponseMock(), type: 'text' }], - largeLists: [], - }; - const filter = filterFieldToList(listData, field); - const expected = listData; - expect(filter).toEqual(expected); - }); - - test('it returns small and large filtered lists of ip_range -> ip', () => { - const field: DataViewFieldBase & { esTypes: string[] } = { - esTypes: ['ip'], - name: 'some-name', - type: 'ip', - }; - const listData: AutocompleteListsData = { - smallLists: [{ ...getListResponseMock(), type: 'ip_range' }], - largeLists: [{ ...getListResponseMock(), type: 'ip_range' }], - }; - const filter = filterFieldToList(listData, field); - const expected = listData; - expect(filter).toEqual(expected); - }); - - test('it returns 1 filtered lists of ip_range -> ip if the 2nd is not compatible type', () => { - const field: DataViewFieldBase & { esTypes: string[] } = { - esTypes: ['ip'], - name: 'some-name', - type: 'ip', - }; - const listData: AutocompleteListsData = { - smallLists: [{ ...getListResponseMock(), type: 'ip_range' }], - largeLists: [{ ...getListResponseMock(), type: 'text' }], - }; - const filter = filterFieldToList(listData, field); - const expected: AutocompleteListsData = { - smallLists: [{ ...getListResponseMock(), type: 'ip_range' }], - largeLists: [], - }; - expect(filter).toEqual(expected); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.ts b/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.ts deleted file mode 100644 index 86d429cc9ef80..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DataViewFieldBase } from '@kbn/es-query'; -import { typeMatch } from '../type_match'; -import { AutocompleteListsData } from '../field_value_lists'; - -/** - * Given an array of lists and optionally a field this will return all - * the lists that match against the field based on the types from the field - * - * NOTE: That we support one additional property from "FieldSpec" located here: - * src/plugins/data/common/index_patterns/fields/types.ts - * This type property is esTypes. If it exists and is on there we will read off the esTypes. - * @param lists The lists to match against the field - * @param field The field to check against the list to see if they are compatible - */ -export const filterFieldToList = ( - lists: AutocompleteListsData, - field?: DataViewFieldBase & { esTypes?: string[] } -): AutocompleteListsData => { - if (field != null) { - const { esTypes = [] } = field; - return { - smallLists: lists.smallLists.filter(({ type }) => - esTypes.some((esType: string) => typeMatch(type, esType)) - ), - largeLists: lists.largeLists.filter(({ type }) => - esTypes.some((esType: string) => typeMatch(type, esType)) - ), - }; - } else { - return { smallLists: [], largeLists: [] }; - } -}; diff --git a/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.test.tsx deleted file mode 100644 index 82ca7f60de24b..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.test.tsx +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { getGenericComboBoxProps } from '.'; - -describe('get_generic_combo_box_props', () => { - test('it returns empty arrays if "options" is empty array', () => { - const result = getGenericComboBoxProps({ - options: [], - selectedOptions: ['option1'], - getLabel: (t: string) => t, - }); - - expect(result).toEqual({ comboOptions: [], labels: [], selectedComboOptions: [] }); - }); - - test('it returns formatted props if "options" array is not empty', () => { - const result = getGenericComboBoxProps({ - options: ['option1', 'option2', 'option3'], - selectedOptions: [], - getLabel: (t: string) => t, - }); - - expect(result).toEqual({ - comboOptions: [ - { - label: 'option1', - }, - { - label: 'option2', - }, - { - label: 'option3', - }, - ], - labels: ['option1', 'option2', 'option3'], - selectedComboOptions: [], - }); - }); - - test('it does not return "selectedOptions" items that do not appear in "options"', () => { - const result = getGenericComboBoxProps({ - options: ['option1', 'option2', 'option3'], - selectedOptions: ['option4'], - getLabel: (t: string) => t, - }); - - expect(result).toEqual({ - comboOptions: [ - { - label: 'option1', - }, - { - label: 'option2', - }, - { - label: 'option3', - }, - ], - labels: ['option1', 'option2', 'option3'], - selectedComboOptions: [], - }); - }); - - test('it returns "selectedOptions" items that do appear in "options"', () => { - const result = getGenericComboBoxProps({ - options: ['option1', 'option2', 'option3'], - selectedOptions: ['option2'], - getLabel: (t: string) => t, - }); - - expect(result).toEqual({ - comboOptions: [ - { - label: 'option1', - }, - { - label: 'option2', - }, - { - label: 'option3', - }, - ], - labels: ['option1', 'option2', 'option3'], - selectedComboOptions: [ - { - label: 'option2', - }, - ], - }); - }); - - test('it returns "disabledOptions" items that do appear in "options" as disabled', () => { - const result = getGenericComboBoxProps({ - options: ['option1', 'option2', 'option3'], - selectedOptions: [], - disabledOptions: ['option2'], - getLabel: (t: string) => t, - }); - - expect(result).toEqual({ - comboOptions: [ - { - label: 'option1', - disabled: false, - }, - { - label: 'option2', - disabled: true, - }, - { - label: 'option3', - disabled: false, - }, - ], - labels: ['option1', 'option2', 'option3'], - selectedComboOptions: [], - }); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.ts b/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.ts deleted file mode 100644 index 2f2a6697c4226..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EuiComboBoxOptionOption } from '@elastic/eui'; - -export interface GetGenericComboBoxPropsReturn { - comboOptions: EuiComboBoxOptionOption[]; - labels: string[]; - selectedComboOptions: EuiComboBoxOptionOption[]; -} - -/** - * Determines the options, selected values and option labels for EUI combo box - * @param options options user can select from - * @param selectedOptions user selection if any - * @param getLabel helper function to know which property to use for labels - */ -export const getGenericComboBoxProps = ({ - getLabel, - options, - selectedOptions, - disabledOptions, -}: { - getLabel: (value: T) => string; - options: T[]; - selectedOptions: T[]; - disabledOptions?: T[]; -}): GetGenericComboBoxPropsReturn => { - const newLabels = options.map(getLabel); - const disabledLabels = disabledOptions?.map(getLabel); - const newComboOptions: EuiComboBoxOptionOption[] = newLabels.map((label) => ({ - label, - disabled: disabledLabels && disabledLabels.length !== 0 && disabledLabels.includes(label), - })); - const newSelectedComboOptions = selectedOptions - .map(getLabel) - .filter((option) => { - return newLabels.indexOf(option) !== -1; - }) - .map((option) => { - return newComboOptions[newLabels.indexOf(option)]; - }); - - return { - comboOptions: newComboOptions, - labels: newLabels, - selectedComboOptions: newSelectedComboOptions, - }; -}; diff --git a/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts b/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts deleted file mode 100644 index 711e7ea87a8e0..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - doesNotExistOperator, - EVENT_FILTERS_OPERATORS, - ALL_OPERATORS, - existsOperator, - isNotOperator, - isOperator, -} from '@kbn/securitysolution-list-utils'; -import { getOperators } from '.'; -import { getField } from '../fields/index.mock'; - -describe('#getOperators', () => { - test('it returns "isOperator" if passed in field is "undefined"', () => { - const operator = getOperators(undefined); - - expect(operator).toEqual([isOperator]); - }); - - test('it returns expected operators when field type is "boolean"', () => { - const operator = getOperators(getField('ssl')); - - expect(operator).toEqual([isOperator, isNotOperator, existsOperator, doesNotExistOperator]); - }); - - test('it returns "isOperator" when field type is "nested"', () => { - const operator = getOperators({ - name: 'nestedField', - scripted: false, - subType: { nested: { path: 'nestedField' } }, - type: 'nested', - }); - - expect(operator).toEqual([isOperator]); - }); - - test('it includes a "matches" operator when field is "file.path.text"', () => { - const operator = getOperators({ - name: 'file.path.text', - type: 'simple', - }); - - expect(operator).toEqual(EVENT_FILTERS_OPERATORS); - }); - - test('it returns all operator types when field type is not null, boolean, or nested', () => { - const operator = getOperators(getField('machine.os.raw')); - - expect(operator).toEqual(ALL_OPERATORS); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts b/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts deleted file mode 100644 index dbb36fd479df6..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DataViewFieldBase } from '@kbn/es-query'; - -import { - ALL_OPERATORS, - EVENT_FILTERS_OPERATORS, - OperatorOption, - doesNotExistOperator, - existsOperator, - isNotOperator, - isOperator, -} from '@kbn/securitysolution-list-utils'; - -/** - * Returns the appropriate operators given a field type - * - * @param field DataViewFieldBase selected field - * - */ -export const getOperators = (field: DataViewFieldBase | undefined): OperatorOption[] => { - if (field == null) { - return [isOperator]; - } else if (field.type === 'boolean') { - return [isOperator, isNotOperator, existsOperator, doesNotExistOperator]; - } else if (field.type === 'nested') { - return [isOperator]; - } else if (field.name === 'file.path.text') { - return EVENT_FILTERS_OPERATORS; - } else { - return ALL_OPERATORS; - } -}; diff --git a/packages/kbn-securitysolution-autocomplete/src/hooks/index.ts b/packages/kbn-securitysolution-autocomplete/src/hooks/index.ts deleted file mode 100644 index 5aa216af4c67e..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/hooks/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './use_field_value_autocomplete'; diff --git a/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.test.ts b/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.test.ts deleted file mode 100644 index 836744f3ede28..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.test.ts +++ /dev/null @@ -1,300 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { waitFor, renderHook } from '@testing-library/react'; -import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; - -import { UseFieldValueAutocompleteReturn, useFieldValueAutocomplete } from '.'; -import { getField } from '../../fields/index.mock'; -import { autocompleteStartMock } from '../../autocomplete/index.mock'; -import { DataViewFieldBase } from '@kbn/es-query'; - -// Copied from "src/plugins/data/common/index_patterns/index_pattern.stub.ts" -// TODO: Remove this in favor of the above if/when it is ported, https://github.com/elastic/kibana/issues/100715 -export const stubIndexPatternWithFields = { - id: '1234', - title: 'logstash-*', - fields: [ - { - name: 'response', - type: 'number', - esTypes: ['integer'], - aggregatable: true, - filterable: true, - searchable: true, - }, - ], -}; - -describe('use_field_value_autocomplete', () => { - const onErrorMock = jest.fn(); - const getValueSuggestionsMock = jest.fn().mockResolvedValue(['value 1', 'value 2']); - - afterEach(() => { - onErrorMock.mockClear(); - getValueSuggestionsMock.mockClear(); - }); - - test('initializes hook', async () => { - const { result } = renderHook(() => - useFieldValueAutocomplete({ - autocompleteService: { - ...autocompleteStartMock, - getValueSuggestions: getValueSuggestionsMock, - }, - fieldValue: '', - indexPattern: undefined, - operatorType: OperatorTypeEnum.MATCH, - query: '', - selectedField: undefined, - }) - ); - await waitFor(() => expect(result.current).toEqual([false, true, [], result.current[3]])); - }); - - test('does not call autocomplete service if "operatorType" is "exists"', async () => { - const { result } = renderHook(() => - useFieldValueAutocomplete({ - autocompleteService: { - ...autocompleteStartMock, - getValueSuggestions: getValueSuggestionsMock, - }, - fieldValue: '', - indexPattern: stubIndexPatternWithFields, - operatorType: OperatorTypeEnum.EXISTS, - query: '', - selectedField: getField('machine.os'), - }) - ); - - await waitFor(() => { - const expectedResult: UseFieldValueAutocompleteReturn = [false, true, [], result.current[3]]; - - expect(result.current).toEqual(expectedResult); - expect(getValueSuggestionsMock).not.toHaveBeenCalled(); - }); - }); - - test('does not call autocomplete service if "selectedField" is undefined', async () => { - const { result } = renderHook(() => - useFieldValueAutocomplete({ - autocompleteService: { - ...autocompleteStartMock, - getValueSuggestions: getValueSuggestionsMock, - }, - fieldValue: '', - indexPattern: stubIndexPatternWithFields, - operatorType: OperatorTypeEnum.EXISTS, - query: '', - selectedField: undefined, - }) - ); - - await waitFor(() => { - const expectedResult: UseFieldValueAutocompleteReturn = [false, true, [], result.current[3]]; - - expect(result.current).toEqual(expectedResult); - expect(getValueSuggestionsMock).not.toHaveBeenCalled(); - }); - }); - - test('does not call autocomplete service if "indexPattern" is undefined', async () => { - const { result } = renderHook(() => - useFieldValueAutocomplete({ - autocompleteService: { - ...autocompleteStartMock, - getValueSuggestions: getValueSuggestionsMock, - }, - fieldValue: '', - indexPattern: undefined, - operatorType: OperatorTypeEnum.EXISTS, - query: '', - selectedField: getField('machine.os'), - }) - ); - - await waitFor(() => { - const expectedResult: UseFieldValueAutocompleteReturn = [false, true, [], result.current[3]]; - - expect(result.current).toEqual(expectedResult); - expect(getValueSuggestionsMock).not.toHaveBeenCalled(); - }); - }); - - test('it uses full path name for nested fields to fetch suggestions', async () => { - const suggestionsMock = jest.fn().mockResolvedValue([]); - - const selectedField: DataViewFieldBase | undefined = getField('nestedField.child'); - if (selectedField == null) { - throw new TypeError('selectedField for this test should always be defined'); - } - - const { signal } = new AbortController(); - renderHook(() => - useFieldValueAutocomplete({ - autocompleteService: { - ...autocompleteStartMock, - getValueSuggestions: suggestionsMock, - }, - fieldValue: '', - indexPattern: stubIndexPatternWithFields, - operatorType: OperatorTypeEnum.MATCH, - query: '', - selectedField: { ...selectedField, name: 'child' }, - }) - ); - - await waitFor(() => - expect(suggestionsMock).toHaveBeenCalledWith({ - field: { ...getField('nestedField.child'), name: 'nestedField.child' }, - indexPattern: { - fields: [ - { - aggregatable: true, - esTypes: ['integer'], - filterable: true, - name: 'response', - searchable: true, - type: 'number', - }, - ], - id: '1234', - title: 'logstash-*', - }, - query: '', - signal, - useTimeRange: false, - }) - ); - }); - - test('returns "isSuggestingValues" of false if field type is boolean', async () => { - const { result } = renderHook(() => - useFieldValueAutocomplete({ - autocompleteService: { - ...autocompleteStartMock, - getValueSuggestions: getValueSuggestionsMock, - }, - fieldValue: '', - indexPattern: stubIndexPatternWithFields, - operatorType: OperatorTypeEnum.MATCH, - query: '', - selectedField: getField('ssl'), - }) - ); - - await waitFor(() => { - const expectedResult: UseFieldValueAutocompleteReturn = [false, false, [], result.current[3]]; - - expect(result.current).toEqual(expectedResult); - expect(getValueSuggestionsMock).not.toHaveBeenCalled(); - }); - }); - - test('returns "isSuggestingValues" of false to note that autocomplete service is not in use if no autocomplete suggestions available', async () => { - const suggestionsMock = jest.fn().mockResolvedValue([]); - - const { result } = renderHook(() => - useFieldValueAutocomplete({ - autocompleteService: { - ...autocompleteStartMock, - getValueSuggestions: suggestionsMock, - }, - fieldValue: '', - indexPattern: stubIndexPatternWithFields, - operatorType: OperatorTypeEnum.MATCH, - query: '', - selectedField: getField('bytes'), - }) - ); - - await waitFor(() => { - const expectedResult: UseFieldValueAutocompleteReturn = [false, false, [], result.current[3]]; - - expect(suggestionsMock).toHaveBeenCalled(); - expect(result.current).toEqual(expectedResult); - }); - }); - - test('returns suggestions', async () => { - const { signal } = new AbortController(); - const { result } = renderHook(() => - useFieldValueAutocomplete({ - autocompleteService: { - ...autocompleteStartMock, - getValueSuggestions: getValueSuggestionsMock, - }, - fieldValue: '', - indexPattern: stubIndexPatternWithFields, - operatorType: OperatorTypeEnum.MATCH, - query: '', - selectedField: getField('@tags'), - }) - ); - - await waitFor(() => { - const expectedResult: UseFieldValueAutocompleteReturn = [ - false, - true, - ['value 1', 'value 2'], - result.current[3], - ]; - - expect(getValueSuggestionsMock).toHaveBeenCalledWith({ - field: getField('@tags'), - indexPattern: stubIndexPatternWithFields, - query: '', - signal, - useTimeRange: false, - }); - expect(result.current).toEqual(expectedResult); - }); - }); - - test('returns new suggestions on subsequent calls', async () => { - const { result } = renderHook(() => - useFieldValueAutocomplete({ - autocompleteService: { - ...autocompleteStartMock, - getValueSuggestions: getValueSuggestionsMock, - }, - fieldValue: '', - indexPattern: stubIndexPatternWithFields, - operatorType: OperatorTypeEnum.MATCH, - query: '', - selectedField: getField('@tags'), - }) - ); - - await waitFor(() => expect(result.current[3]).not.toBeNull()); - - // Added check for typescripts sake, if null, - // would not reach below logic as test would stop above - if (result.current[3] != null) { - result.current[3]({ - fieldSelected: getField('@tags'), - patterns: stubIndexPatternWithFields, - searchQuery: '', - value: 'hello', - }); - } - - await waitFor(() => { - const expectedResult: UseFieldValueAutocompleteReturn = [ - false, - true, - ['value 1', 'value 2'], - result.current[3], - ]; - - expect(getValueSuggestionsMock).toHaveBeenCalledTimes(2); - expect(result.current).toEqual(expectedResult); - }); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.ts b/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.ts deleted file mode 100644 index 9fff2abfd5be5..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.ts +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useEffect, useRef, useState } from 'react'; -import { debounce } from 'lodash'; -import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import { DataViewBase, DataViewFieldBase, getDataViewFieldSubtypeNested } from '@kbn/es-query'; - -// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 -// import { AutocompleteStart } from '../../../../../../../../src/plugins/unified_search/public'; -type AutocompleteStart = any; - -interface FuncArgs { - fieldSelected: DataViewFieldBase | undefined; - patterns: DataViewBase | undefined; - searchQuery: string; - value: string | string[] | undefined; -} - -type Func = (args: FuncArgs) => void; - -export type UseFieldValueAutocompleteReturn = [boolean, boolean, string[], Func | null]; - -export interface UseFieldValueAutocompleteProps { - autocompleteService: AutocompleteStart; - fieldValue: string | string[] | undefined; - indexPattern: DataViewBase | undefined; - operatorType: OperatorTypeEnum; - query: string; - selectedField: DataViewFieldBase | undefined; -} -/** - * Hook for using the field value autocomplete service - */ -export const useFieldValueAutocomplete = ({ - selectedField, - operatorType, - fieldValue, - query, - indexPattern, - autocompleteService, -}: UseFieldValueAutocompleteProps): UseFieldValueAutocompleteReturn => { - const [isLoading, setIsLoading] = useState(false); - const [isSuggestingValues, setIsSuggestingValues] = useState(true); - const [suggestions, setSuggestions] = useState([]); - const updateSuggestions = useRef(null); - - useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); - - const fetchSuggestions = debounce( - async ({ fieldSelected, patterns, searchQuery }: FuncArgs) => { - try { - if (isSubscribed) { - if (fieldSelected == null || patterns == null) { - return; - } - - if (fieldSelected.type === 'boolean') { - setIsSuggestingValues(false); - return; - } - - setIsLoading(true); - const subTypeNested = getDataViewFieldSubtypeNested(fieldSelected); - const field = subTypeNested - ? { - ...fieldSelected, - name: `${subTypeNested.nested.path}.${fieldSelected.name}`, - } - : fieldSelected; - - const newSuggestions = await autocompleteService.getValueSuggestions({ - field, - indexPattern: patterns, - query: searchQuery, - signal: abortCtrl.signal, - useTimeRange: false, - }); - - if (newSuggestions.length === 0) { - setIsSuggestingValues(false); - } - - setIsLoading(false); - setSuggestions([...newSuggestions]); - } - } catch (error) { - if (isSubscribed) { - setSuggestions([]); - setIsLoading(false); - } - } - }, - 500 - ); - - if (operatorType !== OperatorTypeEnum.EXISTS) { - fetchSuggestions({ - fieldSelected: selectedField, - patterns: indexPattern, - searchQuery: query, - value: fieldValue, - }); - } - - updateSuggestions.current = fetchSuggestions; - - return (): void => { - isSubscribed = false; - abortCtrl.abort(); - }; - }, [selectedField, operatorType, fieldValue, indexPattern, query, autocompleteService]); - - return [isLoading, isSuggestingValues, suggestions, updateSuggestions.current]; -}; diff --git a/packages/kbn-securitysolution-autocomplete/src/list_schema/index.mock.ts b/packages/kbn-securitysolution-autocomplete/src/list_schema/index.mock.ts deleted file mode 100644 index e2c2c9b0fe051..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/list_schema/index.mock.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - FoundListSchema, - ListSchema, - FoundListsBySizeSchema, -} from '@kbn/securitysolution-io-ts-list-types'; - -// TODO: Once this mock is available within packages, use it instead, https://github.com/elastic/kibana/issues/100715 -// import { getFoundListSchemaMock } from '../../../../../lists/common/schemas/response/found_list_schema.mock'; -export const getFoundListSchemaMock = (): FoundListSchema => ({ - cursor: '123', - data: [getListResponseMock()], - page: 1, - per_page: 1, - total: 1, -}); - -export const getFoundListsBySizeSchemaMock = (): FoundListsBySizeSchema => ({ - smallLists: [getListResponseMock()], - largeLists: [getListResponseMock()], -}); - -// TODO: Once these mocks are available from packages use it instead, https://github.com/elastic/kibana/issues/100715 -export const DATE_NOW = '2020-04-20T15:25:31.830Z'; -export const USER = 'some user'; -export const IMMUTABLE = false; -export const VERSION = 1; -export const DESCRIPTION = 'some description'; -export const TIE_BREAKER = '6a76b69d-80df-4ab2-8c3e-85f466b06a0e'; -export const LIST_ID = 'some-list-id'; -export const META = {}; -export const TYPE = 'ip'; -export const NAME = 'some name'; - -// TODO: Once this mock is available within packages, use it instead, https://github.com/elastic/kibana/issues/100715 -// import { getListResponseMock } from '../../../../../lists/common/schemas/response/list_schema.mock'; -export const getListResponseMock = (): ListSchema => ({ - '@timestamp': DATE_NOW, - _version: undefined, - created_at: DATE_NOW, - created_by: USER, - description: DESCRIPTION, - deserializer: undefined, - id: LIST_ID, - immutable: IMMUTABLE, - meta: META, - name: NAME, - serializer: undefined, - tie_breaker_id: TIE_BREAKER, - type: TYPE, - updated_at: DATE_NOW, - updated_by: USER, - version: VERSION, -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx deleted file mode 100644 index 4d2112d8f31d1..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx +++ /dev/null @@ -1,255 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; -import { isNotOperator, isOperator } from '@kbn/securitysolution-list-utils'; - -import { OperatorComponent } from '.'; -import { getField } from '../fields/index.mock'; - -describe('operator', () => { - test('it renders disabled if "isDisabled" is true', () => { - const wrapper = mount( - - ); - - expect( - wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"] input`).prop('disabled') - ).toBeTruthy(); - }); - - test('it renders loading if "isLoading" is true', () => { - const wrapper = mount( - - ); - wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"] button`).at(0).simulate('click'); - expect( - wrapper - .find(`EuiComboBoxOptionsList[data-test-subj="operatorAutocompleteComboBox-optionsList"]`) - .prop('isLoading') - ).toBeTruthy(); - }); - - test('it allows user to clear values if "isClearable" is true', () => { - const wrapper = mount( - - ); - - expect(wrapper.find(`button[data-test-subj="comboBoxClearButton"]`).exists()).toBeTruthy(); - }); - - test('it displays "operatorOptions" if param is passed in with items', () => { - const wrapper = mount( - - ); - - expect( - wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') - ).toEqual([{ label: 'is not' }]); - }); - - test('it does not display "operatorOptions" if param is passed in with no items', () => { - const wrapper = mount( - - ); - - expect( - wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') - ).toEqual([ - { - label: 'is', - }, - { - label: 'is not', - }, - { - label: 'is one of', - }, - { - label: 'is not one of', - }, - { - label: 'exists', - }, - { - label: 'does not exist', - }, - { - label: 'is in list', - }, - { - label: 'is not in list', - }, - { - label: 'matches', - }, - { - label: 'does not match', - }, - ]); - }); - - test('it correctly displays selected operator', () => { - const wrapper = mount( - - ); - - expect( - wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(0).props().value - ).toEqual('is'); - }); - - test('it only displays subset of operators if field type is nested', () => { - const wrapper = mount( - - ); - - expect( - wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') - ).toEqual([{ label: 'is' }]); - }); - - test('it only displays subset of operators if field type is boolean', () => { - const wrapper = mount( - - ); - - expect( - wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') - ).toEqual([ - { label: 'is' }, - { label: 'is not' }, - { label: 'exists' }, - { label: 'does not exist' }, - ]); - }); - - test('it only displays subset of operators if field name is "file.path.text"', () => { - const wrapper = mount( - - ); - - expect( - wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') - ).toEqual([ - { label: 'is' }, - { label: 'is not' }, - { label: 'is one of' }, - { label: 'is not one of' }, - { label: 'matches' }, - { label: 'does not match' }, - ]); - }); - - test('it invokes "onChange" when option selected', () => { - const mockOnChange = jest.fn(); - const wrapper = mount( - - ); - - ( - wrapper.find(EuiComboBox).props() as unknown as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - } - ).onChange([{ label: 'is not' }]); - - expect(mockOnChange).toHaveBeenCalledWith([ - { message: 'is not', operator: 'excluded', type: 'match', value: 'is_not' }, - ]); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/operator/index.tsx b/packages/kbn-securitysolution-autocomplete/src/operator/index.tsx deleted file mode 100644 index c3d91c16eae91..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/operator/index.tsx +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { useCallback, useMemo } from 'react'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; -import { OperatorOption } from '@kbn/securitysolution-list-utils'; -import { DataViewFieldBase } from '@kbn/es-query'; - -import { getOperators } from '../get_operators'; -import { - getGenericComboBoxProps, - GetGenericComboBoxPropsReturn, -} from '../get_generic_combo_box_props'; - -const AS_PLAIN_TEXT = { asPlainText: true }; - -interface OperatorState { - isClearable: boolean; - isDisabled: boolean; - isLoading: boolean; - onChange: (arg: OperatorOption[]) => void; - operator: OperatorOption; - operatorInputWidth?: number; - operatorOptions?: OperatorOption[]; - placeholder: string; - selectedField: DataViewFieldBase | undefined; - 'aria-label'?: string; -} - -export const OperatorComponent: React.FC = ({ - isClearable = false, - isDisabled = false, - isLoading = false, - onChange, - operator, - operatorOptions, - operatorInputWidth = 150, - placeholder, - selectedField, - 'aria-label': ariaLabel, -}): JSX.Element => { - const getLabel = useCallback(({ message }: OperatorOption): string => message, []); - const optionsMemo = useMemo( - (): OperatorOption[] => - operatorOptions != null && operatorOptions.length > 0 - ? operatorOptions - : getOperators(selectedField), - [operatorOptions, selectedField] - ); - const selectedOptionsMemo = useMemo( - (): OperatorOption[] => (operator ? [operator] : []), - [operator] - ); - const { comboOptions, labels, selectedComboOptions } = useMemo( - (): GetGenericComboBoxPropsReturn => - getGenericComboBoxProps({ - getLabel, - options: optionsMemo, - selectedOptions: selectedOptionsMemo, - }), - [optionsMemo, selectedOptionsMemo, getLabel] - ); - - const handleValuesChange = useCallback( - (newOptions: EuiComboBoxOptionOption[]): void => { - const newValues: OperatorOption[] = newOptions.map( - ({ label }) => optionsMemo[labels.indexOf(label)] - ); - onChange(newValues); - }, - [labels, onChange, optionsMemo] - ); - - const inputWidth = useMemo(() => { - return { width: `${operatorInputWidth}px` }; - }, [operatorInputWidth]); - - return ( - - ); -}; - -OperatorComponent.displayName = 'Operator'; diff --git a/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.test.ts b/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.test.ts deleted file mode 100644 index aef6fc4acffa2..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { paramContainsSpace } from '.'; - -describe('param_contains_space', () => { - test('should return true if leading spaces were found', () => { - expect(paramContainsSpace(' test')).toBeTruthy(); - }); - test('should return true if trailing spaces were found', () => { - expect(paramContainsSpace('test ')).toBeTruthy(); - }); - test('should return true if both trailing and leading spaces were found', () => { - expect(paramContainsSpace(' test ')).toBeTruthy(); - }); - test('should return true if tabs was found', () => { - expect(paramContainsSpace('\ttest')).toBeTruthy(); - }); - test('should return false if no spaces were found', () => { - expect(paramContainsSpace('test test')).toBeFalsy(); - }); - test('should return false if param is falsy', () => { - expect(paramContainsSpace('')).toBeFalsy(); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.ts b/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.ts deleted file mode 100644 index 996167f20536f..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export const paramContainsSpace = (param: string) => param && param.trim().length !== param.length; diff --git a/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.test.ts b/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.test.ts deleted file mode 100644 index c530bca356cbf..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { paramIsValid } from '.'; -import { getField } from '../fields/index.mock'; -import * as i18n from '../translations'; -import moment from 'moment'; - -describe('params_is_valid', () => { - beforeEach(() => { - // Disable momentJS deprecation warning and it looks like it is not typed either so - // we have to disable the type as well and cannot extend it easily. - ( - moment as unknown as { - suppressDeprecationWarnings: boolean; - } - ).suppressDeprecationWarnings = true; - }); - - afterEach(() => { - // Re-enable momentJS deprecation warning and it looks like it is not typed either so - // we have to disable the type as well and cannot extend it easily. - ( - moment as unknown as { - suppressDeprecationWarnings: boolean; - } - ).suppressDeprecationWarnings = false; - }); - - test('returns no errors if no field has been selected', () => { - const isValid = paramIsValid('', undefined, true, false); - - expect(isValid).toBeUndefined(); - }); - - test('returns error string if user has touched a required input and left empty', () => { - const isValid = paramIsValid(undefined, getField('@timestamp'), true, true); - - expect(isValid).toEqual(i18n.FIELD_REQUIRED_ERR); - }); - - test('returns no errors if required input is empty but user has not yet touched it', () => { - const isValid = paramIsValid(undefined, getField('@timestamp'), true, false); - - expect(isValid).toBeUndefined(); - }); - - test('returns no errors if user has touched an input that is not required and left empty', () => { - const isValid = paramIsValid(undefined, getField('@timestamp'), false, true); - - expect(isValid).toBeUndefined(); - }); - - test('returns no errors if user has touched an input that is not required and left empty string', () => { - const isValid = paramIsValid('', getField('@timestamp'), false, true); - - expect(isValid).toBeUndefined(); - }); - - test('returns no errors if field is of type date and value is valid', () => { - const isValid = paramIsValid('1994-11-05T08:15:30-05:00', getField('@timestamp'), false, true); - - expect(isValid).toBeUndefined(); - }); - - test('returns errors if filed is of type date and value is not valid', () => { - const isValid = paramIsValid('1593478826', getField('@timestamp'), false, true); - - expect(isValid).toEqual(i18n.DATE_ERR); - }); - - test('returns no errors if field is of type number and value is an integer', () => { - const isValid = paramIsValid('4', getField('bytes'), true, true); - - expect(isValid).toBeUndefined(); - }); - - test('returns no errors if field is of type number and value is a float', () => { - const isValid = paramIsValid('4.3', getField('bytes'), true, true); - - expect(isValid).toBeUndefined(); - }); - - test('returns no errors if field is of type number and value is a long', () => { - const isValid = paramIsValid('-9223372036854775808', getField('bytes'), true, true); - - expect(isValid).toBeUndefined(); - }); - - test('returns errors if field is of type number and value is "hello"', () => { - const isValid = paramIsValid('hello', getField('bytes'), true, true); - - expect(isValid).toEqual(i18n.NUMBER_ERR); - }); - - test('returns errors if field is of type number and value is "123abc"', () => { - const isValid = paramIsValid('123abc', getField('bytes'), true, true); - - expect(isValid).toEqual(i18n.NUMBER_ERR); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts b/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts deleted file mode 100644 index 5abde0b36c4c7..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import dateMath from '@kbn/datemath'; -import { DataViewFieldBase } from '@kbn/es-query'; -import { checkEmptyValue } from '../check_empty_value'; - -import * as i18n from '../translations'; - -/** - * Very basic validation for values - * @param param the value being checked - * @param field the selected field - * @param isRequired whether or not an empty value is allowed - * @param touched has field been touched by user - * @returns undefined if valid, string with error message if invalid - */ -export const paramIsValid = ( - param: string | undefined, - field: DataViewFieldBase | undefined, - isRequired: boolean, - touched: boolean -): string | undefined => { - if (field == null) { - return undefined; - } - - const emptyValueError = checkEmptyValue(param, field, isRequired, touched); - if (emptyValueError !== null) { - return emptyValueError; - } - - switch (field.type) { - case 'date': - const moment = dateMath.parse(param ?? ''); - const isDate = Boolean(moment && moment.isValid()); - return isDate ? undefined : i18n.DATE_ERR; - case 'number': - const isNum = param != null && param.trim() !== '' && !isNaN(+param); - return isNum ? undefined : i18n.NUMBER_ERR; - default: - return undefined; - } -}; diff --git a/packages/kbn-securitysolution-autocomplete/src/translations/index.ts b/packages/kbn-securitysolution-autocomplete/src/translations/index.ts deleted file mode 100644 index 01671880d2dcb..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/translations/index.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { i18n } from '@kbn/i18n'; - -export const LOADING = i18n.translate('autocomplete.loadingDescription', { - defaultMessage: 'Loading...', -}); - -export const SELECT_FIELD_FIRST = i18n.translate('autocomplete.selectField', { - defaultMessage: 'Please select a field first...', -}); - -export const FIELD_REQUIRED_ERR = i18n.translate('autocomplete.fieldRequiredError', { - defaultMessage: 'Value cannot be empty', -}); - -export const NUMBER_ERR = i18n.translate('autocomplete.invalidNumberError', { - defaultMessage: 'Not a valid number', -}); - -export const DATE_ERR = i18n.translate('autocomplete.invalidDateError', { - defaultMessage: 'Not a valid date', -}); - -export const BINARY_TYPE_NOT_SUPPORTED = i18n.translate('autocomplete.invalidBinaryType', { - defaultMessage: 'Binary fields are currently unsupported', -}); -export const FIELD_SPACE_WARNING = i18n.translate('autocomplete.fieldSpaceWarning', { - defaultMessage: "Warning: Spaces at the start or end of this value aren't being displayed.", -}); - -export const LISTS_TOOLTIP_INFO = i18n.translate('autocomplete.listsTooltipWarning', { - defaultMessage: "Lists that aren't able to be processed by this rule type will be disabled.", -}); - -export const SEE_DOCUMENTATION = i18n.translate('autocomplete.seeDocumentation', { - defaultMessage: 'See Documentation', -}); - -export const FIELD_CONFLICT_INDICES_WARNING_TITLE = i18n.translate( - 'autocomplete.conflictIndicesWarning.title', - { - defaultMessage: 'Mapping Conflict', - } -); - -export const FIELD_CONFLICT_INDICES_WARNING_DESCRIPTION = i18n.translate( - 'autocomplete.conflictIndicesWarning.description', - { - defaultMessage: - 'This field is defined as different types across the following indices or is unmapped. This can cause unexpected query results.', - } -); - -export const CONFLICT_MULTIPLE_INDEX_DESCRIPTION = (name: string, count: number): string => - i18n.translate('autocomplete.conflictIndicesWarning.index.description', { - defaultMessage: '{name} ({count} indices)', - values: { count, name }, - }); - -export const SHOW_VALUE_LIST_MODAL = i18n.translate('autocomplete.showValueListModal', { - defaultMessage: 'Show value list', -}); - -// eslint-disable-next-line import/no-default-export -export default { - LOADING, - SELECT_FIELD_FIRST, - FIELD_REQUIRED_ERR, - NUMBER_ERR, - DATE_ERR, - FIELD_SPACE_WARNING, - BINARY_TYPE_NOT_SUPPORTED, -}; diff --git a/packages/kbn-securitysolution-autocomplete/src/type_match/index.test.ts b/packages/kbn-securitysolution-autocomplete/src/type_match/index.test.ts deleted file mode 100644 index 15c7c3f580da6..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/type_match/index.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { typeMatch } from '.'; - -describe('type_match', () => { - test('ip -> ip is true', () => { - expect(typeMatch('ip', 'ip')).toEqual(true); - }); - - test('keyword -> keyword is true', () => { - expect(typeMatch('keyword', 'keyword')).toEqual(true); - }); - - test('text -> text is true', () => { - expect(typeMatch('text', 'text')).toEqual(true); - }); - - test('ip_range -> ip is true', () => { - expect(typeMatch('ip_range', 'ip')).toEqual(true); - }); - - test('date_range -> date is true', () => { - expect(typeMatch('date_range', 'date')).toEqual(true); - }); - - test('double_range -> double is true', () => { - expect(typeMatch('double_range', 'double')).toEqual(true); - }); - - test('float_range -> float is true', () => { - expect(typeMatch('float_range', 'float')).toEqual(true); - }); - - test('integer_range -> integer is true', () => { - expect(typeMatch('integer_range', 'integer')).toEqual(true); - }); - - test('long_range -> long is true', () => { - expect(typeMatch('long_range', 'long')).toEqual(true); - }); - - test('ip -> date is false', () => { - expect(typeMatch('ip', 'date')).toEqual(false); - }); - - test('long -> float is false', () => { - expect(typeMatch('long', 'float')).toEqual(false); - }); - - test('integer -> long is false', () => { - expect(typeMatch('integer', 'long')).toEqual(false); - }); -}); diff --git a/packages/kbn-securitysolution-autocomplete/src/type_match/index.ts b/packages/kbn-securitysolution-autocomplete/src/type_match/index.ts deleted file mode 100644 index 4d5899a376a08..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/src/type_match/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { Type } from '@kbn/securitysolution-io-ts-list-types'; - -/** - * Given an input list type and a string based ES type this will match - * if they're exact or if they are compatible with a range - * @param type The type to match against the esType - * @param esType The ES type to match with - */ -export const typeMatch = (type: Type, esType: string): boolean => { - return ( - type === esType || - (type === 'ip_range' && esType === 'ip') || - (type === 'date_range' && esType === 'date') || - (type === 'double_range' && esType === 'double') || - (type === 'float_range' && esType === 'float') || - (type === 'integer_range' && esType === 'integer') || - (type === 'long_range' && esType === 'long') - ); -}; diff --git a/packages/kbn-securitysolution-autocomplete/tsconfig.json b/packages/kbn-securitysolution-autocomplete/tsconfig.json deleted file mode 100644 index f7df7da6f06ad..0000000000000 --- a/packages/kbn-securitysolution-autocomplete/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": ["jest", "node"] - }, - "include": [ - "**/*.ts", - "**/*.tsx", - ], - "kbn_references": [ - "@kbn/datemath", - "@kbn/es-query", - "@kbn/i18n", - "@kbn/securitysolution-io-ts-list-types", - "@kbn/securitysolution-list-hooks", - "@kbn/securitysolution-list-utils", - "@kbn/doc-links", - "@kbn/securitysolution-utils", - ], - "exclude": [ - "target/**/*", - ], -} diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.gen.ts b/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.gen.ts deleted file mode 100644 index 42a3b67106c02..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.gen.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Create endpoint list API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { EndpointList } from '../model/endpoint_list_common.gen'; - -export type CreateEndpointListResponse = z.infer; -export const CreateEndpointListResponse = EndpointList; diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.schema.yaml b/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.schema.yaml deleted file mode 100644 index b2ca0f563617d..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.schema.yaml +++ /dev/null @@ -1,45 +0,0 @@ -openapi: 3.0.0 -info: - title: Create endpoint list API endpoint - version: '2023-10-31' -paths: - /api/endpoint_list: - post: - x-labels: [serverless, ess] - x-codegen-enabled: true - operationId: CreateEndpointList - summary: Create an endpoint exception list - description: Create an endpoint exception list, which groups endpoint exception list items. If an endpoint exception list already exists, an empty response is returned. - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/endpoint_list_common.schema.yaml#/components/schemas/EndpointList' - 400: - description: Invalid input data - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Insufficient privileges - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 500: - description: Internal server error - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.schema.yaml b/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.schema.yaml deleted file mode 100644 index 69db506169187..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.schema.yaml +++ /dev/null @@ -1,64 +0,0 @@ -openapi: 3.0.0 -info: - title: Delete endpoint list item API endpoint - version: '2023-10-31' -paths: - /api/endpoint_list/items: - delete: - x-labels: [serverless, ess] - x-codegen-enabled: true - operationId: DeleteEndpointListItem - summary: Delete an endpoint exception list item - description: Delete an endpoint exception list item using the `id` or `item_id` field. - parameters: - - name: id - in: query - required: false - description: Either `id` or `item_id` must be specified - schema: - $ref: '../../../kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemId' - - name: item_id - in: query - required: false - description: Either `id` or `item_id` must be specified - schema: - $ref: '../../../kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemHumanId' - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/endpoint_list_common.schema.yaml#/components/schemas/EndpointListItem' - 400: - description: Invalid input data - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Insufficient privileges - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: Endpoint list item not found - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.schema.yaml b/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.schema.yaml deleted file mode 100644 index 6dc2fcaa7e87a..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.schema.yaml +++ /dev/null @@ -1,113 +0,0 @@ -openapi: 3.0.0 -info: - title: Find endpoint list items API endpoint - version: '2023-10-31' -paths: - /api/endpoint_list/items/_find: - get: - x-labels: [serverless, ess] - x-codegen-enabled: true - operationId: FindEndpointListItems - summary: Get endpoint exception list items - description: Get a list of all endpoint exception list items. - parameters: - - name: filter - in: query - required: false - description: | - Filters the returned results according to the value of the specified field, - using the `:` syntax. - schema: - $ref: '#/components/schemas/FindEndpointListItemsFilter' - - name: page - in: query - required: false - description: The page number to return - schema: - type: integer - minimum: 0 - - name: per_page - in: query - required: false - description: The number of exception list items to return per page - schema: - type: integer - minimum: 0 - - name: sort_field - in: query - required: false - description: Determines which field is used to sort the results - schema: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - - name: sort_order - in: query - required: false - description: Determines the sort order, which can be `desc` or `asc` - schema: - type: string - enum: [desc, asc] - responses: - 200: - description: Successful response - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '../model/endpoint_list_common.schema.yaml#/components/schemas/EndpointListItem' - page: - type: integer - minimum: 0 - per_page: - type: integer - minimum: 0 - total: - type: integer - minimum: 0 - pit: - type: string - required: - - data - - page - - per_page - - total - 400: - description: Invalid input data - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Insufficient privileges - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: Endpoint list not found - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - -components: - schemas: - FindEndpointListItemsFilter: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/index.ts b/packages/kbn-securitysolution-endpoint-exceptions-common/api/index.ts deleted file mode 100644 index c71b02c448db8..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './create_endpoint_list/create_endpoint_list.gen'; -export * from './create_endpoint_list_item/create_endpoint_list_item.gen'; -export * from './read_endpoint_list_item/read_endpoint_list_item.gen'; -export * from './update_endpoint_list_item/update_endpoint_list_item.gen'; -export * from './delete_endpoint_list_item/delete_endpoint_list_item.gen'; -export * from './find_endpoint_list_item/find_endpoint_list_item.gen'; diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.gen.ts b/packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.gen.ts deleted file mode 100644 index 6c8093246b1a6..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.gen.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Common Exception List Attributes - * version: not applicable - */ - -import { z } from '@kbn/zod'; - -import { - ExceptionList, - ExceptionListItem, -} from '@kbn/securitysolution-exceptions-common/api/model/exception_list_common.gen'; - -export type EndpointList = z.infer; -export const EndpointList = z.union([ExceptionList, z.object({}).strict()]); - -export type EndpointListItem = z.infer; -export const EndpointListItem = ExceptionListItem; diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.schema.yaml b/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.schema.yaml deleted file mode 100644 index 8a4e0b291c76f..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.schema.yaml +++ /dev/null @@ -1,66 +0,0 @@ -openapi: 3.0.0 -info: - title: Read endpoint list item API endpoint - version: '2023-10-31' -paths: - /api/endpoint_list/items: - get: - x-labels: [serverless, ess] - x-codegen-enabled: true - operationId: ReadEndpointListItem - summary: Get an endpoint exception list item - description: Get the details of an endpoint exception list item using the `id` or `item_id` field. - parameters: - - name: id - in: query - required: false - description: Either `id` or `item_id` must be specified - schema: - $ref: '../../../kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemId' - - name: item_id - in: query - required: false - description: Either `id` or `item_id` must be specified - schema: - $ref: '../../../kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemHumanId' - responses: - 200: - description: Successful response - content: - application/json: - schema: - type: array - items: - $ref: '../model/endpoint_list_common.schema.yaml#/components/schemas/EndpointListItem' - 400: - description: Invalid input data - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Insufficient privileges - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: Endpoint list item not found - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/package.json b/packages/kbn-securitysolution-endpoint-exceptions-common/package.json deleted file mode 100644 index 78470be1d4e4f..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "description": "OpenAPI Endpoint Exceptions Common", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "name": "@kbn/securitysolution-endpoint-exceptions-common", - "private": true, - "version": "1.0.0", - "scripts": { - "openapi:generate": "node scripts/openapi_generate", - "openapi:bundle": "node scripts/openapi_bundle" - } -} diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js b/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js deleted file mode 100644 index e5a02965593c3..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -require('../../../src/setup_node_env'); -const { join, resolve } = require('path'); -const { bundle } = require('@kbn/openapi-bundler'); - -const ROOT = resolve(__dirname, '..'); - -(async () => { - await bundle({ - sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), - outputFilePath: join( - ROOT, - 'docs/openapi/serverless/security_solution_endpoint_exceptions_api_{version}.bundled.schema.yaml' - ), - options: { - includeLabels: ['serverless'], - prototypeDocument: { - info: { - title: 'Security Endpoint Exceptions API (Elastic Cloud Serverless)', - description: 'Endpoint Exceptions API allow you to manage Endpoint lists.', - }, - tags: [ - { - name: 'Security Endpoint Exceptions API', - 'x-displayName': 'Security endpoint exceptions', - description: - "Endpoint Exceptions API allows you to manage detection rule endpoint exceptions to prevent a rule from generating an alert from incoming events even when the rule's other criteria are met.", - }, - ], - }, - }, - }); - - await bundle({ - sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), - outputFilePath: join( - ROOT, - 'docs/openapi/ess/security_solution_endpoint_exceptions_api_{version}.bundled.schema.yaml' - ), - options: { - includeLabels: ['ess'], - prototypeDocument: { - info: { - title: 'Security Endpoint Exceptions API (Elastic Cloud and self-hosted)', - description: 'Endpoint Exceptions API allow you to manage Endpoint lists.', - }, - tags: [ - { - name: 'Security Endpoint Exceptions API', - 'x-displayName': 'Security endpoint exceptions', - description: - "Endpoint Exceptions API allows you to manage detection rule endpoint exceptions to prevent a rule from generating an alert from incoming events even when the rule's other criteria are met.", - }, - ], - }, - }, - }); -})(); diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_generate.js b/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_generate.js deleted file mode 100644 index bca85786a518f..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_generate.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -require('../../../src/setup_node_env'); -const { join, resolve } = require('path'); -const { generate } = require('@kbn/openapi-generator'); -const { REPO_ROOT } = require('@kbn/repo-info'); - -const ROOT = resolve(__dirname, '..'); - -(async () => { - await generate({ - title: 'OpenAPI Endpoint Exceptions API Schemas', - rootDir: ROOT, - sourceGlob: './api/**/*.schema.yaml', - templateName: 'zod_operation_schema', - }); - - await generate({ - title: 'Endpoint Exceptions API client for tests', - rootDir: ROOT, - sourceGlob: './api/**/*.schema.yaml', - templateName: 'api_client_supertest', - skipLinting: true, - bundle: { - outFile: join( - REPO_ROOT, - 'x-pack/test/api_integration/services/security_solution_endpoint_exceptions_api.gen.ts' - ), - }, - }); -})(); diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/tsconfig.json b/packages/kbn-securitysolution-endpoint-exceptions-common/tsconfig.json deleted file mode 100644 index 7e3c3fd7396dc..0000000000000 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "outDir": "target/types", - "types": ["jest", "node"] - }, - "exclude": ["target/**/*"], - "extends": "../../tsconfig.base.json", - "include": ["**/*.ts"], - "kbn_references": [ - "@kbn/securitysolution-exceptions-common", - "@kbn/openapi-common", - "@kbn/zod", - ] -} diff --git a/packages/kbn-securitysolution-es-utils/jest.config.js b/packages/kbn-securitysolution-es-utils/jest.config.js deleted file mode 100644 index 5d52b2d390b57..0000000000000 --- a/packages/kbn-securitysolution-es-utils/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-es-utils'], -}; diff --git a/packages/kbn-securitysolution-es-utils/tsconfig.json b/packages/kbn-securitysolution-es-utils/tsconfig.json deleted file mode 100644 index e584d504cc9c0..0000000000000 --- a/packages/kbn-securitysolution-es-utils/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "exclude": [ - "target/**/*", - ], - "kbn_references": [ - "@kbn/zod-helpers", - "@kbn/zod", - ] -} diff --git a/packages/kbn-securitysolution-exception-list-components/index.ts b/packages/kbn-securitysolution-exception-list-components/index.ts deleted file mode 100644 index 0e11a4694384d..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './src/search_bar'; -export * from './src/empty_viewer_state'; -export * from './src/pagination/pagination'; -// export * from './src/exceptions_utility/exceptions_utility'; -export * from './src/exception_items'; -export * from './src/exception_item_card'; -export * from './src/value_with_space_warning'; -export * from './src/types'; -export * from './src/list_header'; -export * from './src/header_menu'; -export * from './src/generate_linked_rules_menu_item'; -export * from './src/wildcard_with_wrong_operator_callout'; -export * from './src/partial_code_signature_callout'; diff --git a/packages/kbn-securitysolution-exception-list-components/jest.config.js b/packages/kbn-securitysolution-exception-list-components/jest.config.js deleted file mode 100644 index e9d4ad8ad8487..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/jest.config.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-exception-list-components'], - coverageReporters: ['text', 'html'], - collectCoverageFrom: [ - '/packages/kbn-securitysolution-exception-list-components/**/*.{ts,tsx}', - '!/packages/kbn-securitysolution-exception-list-components/**/*.test', - '!/packages/kbn-securitysolution-exception-list-components/**/types/*', - '!/packages/kbn-securitysolution-exception-list-components/**/*.type', - '!/packages/kbn-securitysolution-exception-list-components/**/*.styles', - '!/packages/kbn-securitysolution-exception-list-components/**/mocks/*', - '!/packages/kbn-securitysolution-exception-list-components/**/*.config', - '!/packages/kbn-securitysolution-exception-list-components/**/translations', - '!/packages/kbn-securitysolution-exception-list-components/**/types/*', - ], - setupFilesAfterEnv: [ - '/packages/kbn-securitysolution-exception-list-components/setup_test.ts', - ], -}; diff --git a/packages/kbn-securitysolution-exception-list-components/package.json b/packages/kbn-securitysolution-exception-list-components/package.json deleted file mode 100644 index 0b99a01c071e8..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/securitysolution-exception-list-components", - "private": true, - "version": "1.0.0", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "sideEffects": false -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-exception-list-components/setup_test.ts b/packages/kbn-securitysolution-exception-list-components/setup_test.ts deleted file mode 100644 index 5ebc6d3dac1ca..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/setup_test.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -// eslint-disable-next-line import/no-extraneous-dependencies -import '@testing-library/jest-dom'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/custom.d.ts b/packages/kbn-securitysolution-exception-list-components/src/custom.d.ts deleted file mode 100644 index aa99593b9e877..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/custom.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -declare module '*.svg' { - const content: string; - // eslint-disable-next-line import/no-default-export - export default content; -} diff --git a/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/index.tsx deleted file mode 100644 index e9996e814c34a..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/index.tsx +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { useMemo } from 'react'; -import type { FC } from 'react'; -import { css } from '@emotion/react'; -import { - EuiSkeletonText, - EuiImage, - EuiEmptyPrompt, - EuiButton, - useEuiTheme, - EuiPanel, -} from '@elastic/eui'; -import type { ExpressionColor } from '@elastic/eui/src/components/expression/expression'; -import type { EuiFacetGroupLayout } from '@elastic/eui/src/components/facet/facet_group'; -import { euiThemeVars } from '@kbn/ui-theme'; -import { ListTypeText, ViewerStatus } from '../types'; -import * as i18n from '../translations'; -import illustration from '../assets/images/illustration_product_no_results_magnifying_glass.svg'; - -interface EmptyViewerStateProps { - title?: string; - body?: string; - buttonText?: string; - listType?: ListTypeText; - isReadOnly: boolean; - viewerStatus: ViewerStatus; - onEmptyButtonStateClick?: () => void | null; -} - -const panelCss = css` - margin: ${euiThemeVars.euiSizeL} 0; - padding: ${euiThemeVars.euiSizeL} 0; -`; -const EmptyViewerStateComponent: FC = ({ - title, - body, - buttonText, - listType, - isReadOnly, - viewerStatus, - onEmptyButtonStateClick, -}) => { - const { euiTheme } = useEuiTheme(); - - const euiEmptyPromptProps = useMemo(() => { - switch (viewerStatus) { - case ViewerStatus.ERROR: { - return { - color: 'danger' as ExpressionColor, - iconType: 'error', - title: ( -

{title || i18n.EMPTY_VIEWER_STATE_ERROR_TITLE}

- ), - body:

{body || i18n.EMPTY_VIEWER_STATE_ERROR_BODY}

, - 'data-test-subj': 'errorViewerState', - }; - } - case ViewerStatus.EMPTY: - return { - color: 'subdued' as ExpressionColor, - iconType: 'plusInCircle', - iconColor: euiTheme.colors.darkestShade, - title: ( -

{title || i18n.EMPTY_VIEWER_STATE_EMPTY_TITLE}

- ), - body:

{body || i18n.EMPTY_VIEWER_STATE_EMPTY_BODY}

, - 'data-test-subj': 'emptyViewerState', - actions: [ - - {buttonText || i18n.EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON(listType || 'rule')} - , - ], - }; - case ViewerStatus.EMPTY_SEARCH: - return { - color: 'plain' as ExpressionColor, - layout: 'horizontal' as EuiFacetGroupLayout, - hasBorder: true, - hasShadow: false, - icon: , - title: ( -

- {title || i18n.EMPTY_VIEWER_STATE_EMPTY_SEARCH_TITLE} -

- ), - body: ( -

- {body || i18n.EMPTY_VIEWER_STATE_EMPTY_SEARCH_BODY} -

- ), - 'data-test-subj': 'emptySearchViewerState', - }; - } - }, [ - viewerStatus, - euiTheme.colors.darkestShade, - title, - body, - onEmptyButtonStateClick, - isReadOnly, - buttonText, - listType, - ]); - - return ( - - - - - - ); -}; - -export const EmptyViewerState = React.memo(EmptyViewerStateComponent); - -EmptyViewerState.displayName = 'EmptyViewerState'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx deleted file mode 100644 index d2e5ac0577af3..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { memo } from 'react'; -import type { EuiCommentProps } from '@elastic/eui'; -import { EuiAccordion, EuiCommentList, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; -import { css } from '@emotion/react'; -import { euiThemeVars } from '@kbn/ui-theme'; -import * as i18n from '../translations'; - -const accordionCss = css` - color: ${euiThemeVars.euiColorPrimary}; -`; - -export interface ExceptionItemCardCommentsProps { - comments: EuiCommentProps[]; - dataTestSubj?: string; -} - -export const ExceptionItemCardComments = memo( - ({ comments, dataTestSubj }) => { - if (!comments.length) return null; - return ( - - - {i18n.exceptionItemCardCommentsAccordion(comments.length)} - - } - arrowDisplay="none" - data-test-subj="exceptionItemCardComments" - > - - - - - - ); - } -); - -ExceptionItemCardComments.displayName = 'ExceptionItemCardComments'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.styles.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.styles.tsx deleted file mode 100644 index 8a089df54f2f6..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.styles.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { cx } from '@emotion/css'; -import { css } from '@emotion/react'; -import { euiThemeVars } from '@kbn/ui-theme'; - -// TODO check font Roboto Mono -export const nestedGroupSpaceCss = css` - margin-left: ${euiThemeVars.euiSizeXL}; - margin-bottom: ${euiThemeVars.euiSizeXS}; - padding-top: ${euiThemeVars.euiSizeXS}; -`; - -export const borderCss = cx( - 'eui-xScroll', - ` - border: 1px; - border-color: #d3dae6; - border-style: solid; -` -); - -export const valueContainerCss = css` - display: flex; - align-items: center; - margin-left: ${euiThemeVars.euiSizeS}; -`; -export const expressionContainerCss = css` - display: flex; - align-items: center; -`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/index.tsx deleted file mode 100644 index b765439116ced..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/index.tsx +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { ElementType, FC, memo } from 'react'; -import { EuiExpression, EuiToken, EuiFlexGroup } from '@elastic/eui'; -import { ListOperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import { - nestedGroupSpaceCss, - valueContainerCss, - expressionContainerCss, -} from '../conditions.styles'; -import type { Entry } from '../types'; -import * as i18n from '../../translations'; -import { getValue, getValueExpression } from './entry_content.helper'; - -interface EntryContentProps { - entry: Entry; - index: number; - isNestedEntry?: boolean; - dataTestSubj?: string; - showValueListModal: ElementType; -} - -export const EntryContent: FC = memo( - ({ entry, index, isNestedEntry = false, dataTestSubj, showValueListModal }) => { - const { field, type } = entry; - const value = getValue(entry); - const operator = 'operator' in entry ? entry.operator : ''; - - const entryKey = `${field}${type}${value}${index}`; - return ( -
-
- {isNestedEntry ? ( - - - -
- - {getValueExpression( - type as ListOperatorTypeEnum, - operator, - value, - showValueListModal - )} -
-
- ) : ( - <> - - - {getValueExpression( - type as ListOperatorTypeEnum, - operator, - value, - showValueListModal - )} - - )} -
-
- ); - } -); -EntryContent.displayName = 'EntryContent'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx deleted file mode 100644 index f472402adddc4..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { memo } from 'react'; -import { EuiPanel } from '@elastic/eui'; - -import { borderCss } from './conditions.styles'; -import { EntryContent } from './entry_content'; -import { OsCondition } from './os_conditions'; -import type { CriteriaConditionsProps, Entry } from './types'; - -export const ExceptionItemCardConditions = memo( - ({ os, entries, dataTestSubj, showValueListModal }) => { - return ( - - {os?.length ? : null} - {entries.map((entry: Entry, index: number) => { - const nestedEntries = 'entries' in entry ? entry.entries : []; - return ( -
- - {nestedEntries?.length - ? nestedEntries.map((nestedEntry: Entry, nestedIndex: number) => ( - - )) - : null} -
- ); - })} -
- ); - } -); -ExceptionItemCardConditions.displayName = 'ExceptionItemCardConditions'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/index.tsx deleted file mode 100644 index 0d8285924c314..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { memo, useMemo } from 'react'; -import { EuiExpression } from '@elastic/eui'; - -import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { OS_LABELS } from '../conditions.config'; -import * as i18n from '../../translations'; - -export interface OsConditionsProps { - dataTestSubj?: string; - os: ExceptionListItemSchema['os_types']; -} - -export const OsCondition = memo(({ os, dataTestSubj }) => { - const osLabel = useMemo(() => { - return os.map((osValue) => OS_LABELS[osValue] ?? osValue).join(', '); - }, [os]); - return osLabel ? ( -
- - - - -
- ) : null; -}); -OsCondition.displayName = 'OsCondition'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/types.ts b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/types.ts deleted file mode 100644 index 0400ca6548d9f..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/types.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { - EntryExists, - EntryList, - EntryMatch, - EntryMatchAny, - EntryMatchWildcard, - EntryNested, - ExceptionListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { ElementType } from 'react'; - -export type Entry = - | EntryExists - | EntryList - | EntryMatch - | EntryMatchAny - | EntryMatchWildcard - | EntryNested; - -export type Entries = ExceptionListItemSchema['entries']; -export interface CriteriaConditionsProps { - entries: Entries; - dataTestSubj: string; - os?: ExceptionListItemSchema['os_types']; - showValueListModal: ElementType; -} diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx deleted file mode 100644 index 72b02cc79a791..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { memo } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; -import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { HeaderMenu } from '../../header_menu'; - -export interface ExceptionItemCardHeaderProps { - item: ExceptionListItemSchema; - actions: Array<{ key: string; icon: string; label: string | boolean; onClick: () => void }>; - disableActions?: boolean; - dataTestSubj: string; -} - -export const ExceptionItemCardHeader = memo( - ({ item, actions, disableActions = false, dataTestSubj }) => { - return ( - - - -

{item.name}

-
-
- - - -
- ); - } -); - -ExceptionItemCardHeader.displayName = 'ExceptionItemCardHeader'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts deleted file mode 100644 index 26af377092336..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './conditions'; -export * from './header'; -export * from './meta'; -export * from './comments'; -export * from './exception_item_card'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.test.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.test.tsx deleted file mode 100644 index cbb48e172322e..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { render } from '@testing-library/react'; -import { MetaInfoDetails } from '.'; - -describe('MetaInfoDetails', () => { - it('should render lastUpdate as string', () => { - const wrapper = render( - - ); - expect(wrapper.container).toMatchSnapshot(); - expect(wrapper.getByTestId('MetaInfoDetailslastUpdate')).toHaveTextContent('last update'); - }); - it('should render lastUpdate as JSX Element', () => { - const wrapper = render( - Last update value

} - lastUpdateValue="value" - /> - ); - expect(wrapper.container).toMatchSnapshot(); - expect(wrapper.getByTestId('MetaInfoDetailslastUpdate')).toHaveTextContent('Last update value'); - }); -}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/index.tsx deleted file mode 100644 index cc9eaa813aa9b..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/index.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { memo } from 'react'; -import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; -import { css } from '@emotion/react'; -import { euiThemeVars } from '@kbn/ui-theme'; -import * as i18n from '../../translations'; - -interface MetaInfoDetailsProps { - label: string; - lastUpdate: JSX.Element | string; - lastUpdateValue?: string; - dataTestSubj?: string; -} - -const euiBadgeFontFamily = css` - font-family: ${euiThemeVars.euiFontFamily}; -`; -export const MetaInfoDetails = memo( - ({ label, lastUpdate, lastUpdateValue, dataTestSubj }) => { - return ( - - - - {label} - - - - - {lastUpdate} - - - {lastUpdateValue != null && ( - <> - - - {i18n.EXCEPTION_ITEM_CARD_META_BY} - - - - - - - {lastUpdateValue} - - - - - - )} - - ); - } -); - -MetaInfoDetails.displayName = 'MetaInfoDetails'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx deleted file mode 100644 index d9c0f84b02d0f..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { memo, useMemo } from 'react'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { css } from '@emotion/react'; -import { euiThemeVars } from '@kbn/ui-theme'; -import * as i18n from '../translations'; -import type { Rule } from '../../types'; -import { MetaInfoDetails } from './details_info'; -import { HeaderMenu } from '../../header_menu'; -import { generateLinkedRulesMenuItems } from '../../generate_linked_rules_menu_item'; - -const itemCss = css` - border-right: 1px solid #d3dae6; - padding: ${euiThemeVars.euiSizeS} ${euiThemeVars.euiSizeM} ${euiThemeVars.euiSizeS} 0; -`; - -export interface ExceptionItemCardMetaInfoProps { - item: ExceptionListItemSchema; - rules: Rule[]; - dataTestSubj: string; - formattedDateComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common -} - -export const ExceptionItemCardMetaInfo = memo( - ({ item, rules, dataTestSubj, securityLinkAnchorComponent, formattedDateComponent }) => { - const FormattedDateComponent = formattedDateComponent; - - const referencedLinks = useMemo( - () => - generateLinkedRulesMenuItems({ - dataTestSubj, - linkedRules: rules, - securityLinkAnchorComponent, - }), - [dataTestSubj, rules, securityLinkAnchorComponent] - ); - - const isExpired = useMemo( - () => (item.expire_time ? new Date(item.expire_time) <= new Date() : false), - [item] - ); - - return ( - - {FormattedDateComponent !== null && ( - <> - - - } - lastUpdateValue={item.created_by} - dataTestSubj={`${dataTestSubj || ''}CreatedBy`} - /> - - - - - } - lastUpdateValue={item.updated_by} - dataTestSubj={`${dataTestSubj || ''}UpdatedBy`} - /> - - {item.expire_time != null && ( - <> - - - } - dataTestSubj={`${dataTestSubj || ''}ExpireTime`} - /> - - - )} - - )} - - - - - ); - } -); -ExceptionItemCardMetaInfo.displayName = 'ExceptionItemCardMetaInfo'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/translations.ts b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/translations.ts deleted file mode 100644 index 78a0dac775cf3..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/translations.ts +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { i18n } from '@kbn/i18n'; - -export const exceptionItemCardEditButton = (listType: string) => - i18n.translate('exceptionList-components.exceptions.exceptionItem.card.editItemButton', { - values: { listType }, - defaultMessage: 'Edit {listType} exception', - }); - -export const exceptionItemCardDeleteButton = (listType: string) => - i18n.translate('exceptionList-components.exceptions.exceptionItem.card.deleteItemButton', { - values: { listType }, - defaultMessage: 'Delete {listType} exception', - }); - -export const EXCEPTION_ITEM_CARD_CREATED_LABEL = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.createdLabel', - { - defaultMessage: 'Created', - } -); - -export const EXCEPTION_ITEM_CARD_UPDATED_LABEL = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.updatedLabel', - { - defaultMessage: 'Updated', - } -); - -export const EXCEPTION_ITEM_CARD_EXPIRES_LABEL = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.expiresLabel', - { - defaultMessage: 'Expires at', - } -); - -export const EXCEPTION_ITEM_CARD_EXPIRED_LABEL = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.expiredLabel', - { - defaultMessage: 'Expired at', - } -); - -export const EXCEPTION_ITEM_CARD_META_BY = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.metaDetailsBy', - { - defaultMessage: 'by', - } -); - -export const exceptionItemCardCommentsAccordion = (comments: number) => - i18n.translate('exceptionList-components.exceptions.exceptionItem.card.showCommentsLabel', { - values: { comments }, - defaultMessage: 'Show {comments, plural, =1 {comment} other {comments}} ({comments})', - }); - -export const CONDITION_OPERATOR_TYPE_MATCH = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.matchOperator', - { - defaultMessage: 'IS', - } -); - -export const CONDITION_OPERATOR_TYPE_NOT_MATCH = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.matchOperator.not', - { - defaultMessage: 'IS NOT', - } -); - -export const CONDITION_OPERATOR_TYPE_WILDCARD_MATCHES = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.wildcardMatchesOperator', - { - defaultMessage: 'MATCHES', - } -); - -export const CONDITION_OPERATOR_TYPE_WILDCARD_DOES_NOT_MATCH = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.wildcardDoesNotMatchOperator', - { - defaultMessage: 'DOES NOT MATCH', - } -); - -export const CONDITION_OPERATOR_TYPE_NESTED = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.nestedOperator', - { - defaultMessage: 'has', - } -); - -export const CONDITION_OPERATOR_TYPE_MATCH_ANY = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.matchAnyOperator', - { - defaultMessage: 'is one of', - } -); - -export const CONDITION_OPERATOR_TYPE_NOT_MATCH_ANY = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.matchAnyOperator.not', - { - defaultMessage: 'is not one of', - } -); - -export const CONDITION_OPERATOR_TYPE_EXISTS = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.existsOperator', - { - defaultMessage: 'exists', - } -); - -export const CONDITION_OPERATOR_TYPE_DOES_NOT_EXIST = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.existsOperator.not', - { - defaultMessage: 'does not exist', - } -); - -export const CONDITION_OPERATOR_TYPE_LIST = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.listOperator', - { - defaultMessage: 'included in', - } -); - -export const CONDITION_OPERATOR_TYPE_NOT_IN_LIST = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.listOperator.not', - { - defaultMessage: 'is not included in', - } -); - -export const CONDITION_AND = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.and', - { - defaultMessage: 'AND', - } -); - -export const CONDITION_OS = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.os', - { - defaultMessage: 'OS', - } -); - -export const OS_WINDOWS = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.windows', - { - defaultMessage: 'Windows', - } -); - -export const OS_LINUX = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.linux', - { - defaultMessage: 'Linux', - } -); - -export const OS_MAC = i18n.translate( - 'exceptionList-components.exceptions.exceptionItem.card.conditions.macos', - { - defaultMessage: 'Mac', - } -); - -export const AFFECTED_RULES = (numRules: number) => - i18n.translate('exceptionList-components.exceptions.card.exceptionItem.affectedRules', { - values: { numRules }, - defaultMessage: 'Affects {numRules} {numRules, plural, =1 {rule} other {rules}}', - }); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx deleted file mode 100644 index edad9aecdb0d0..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { ElementType } from 'react'; -import { css } from '@emotion/react'; -import type { FC } from 'react'; -import { EuiCommentProps, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - -import type { - CommentsArray, - ExceptionListItemSchema, - ExceptionListTypeEnum, -} from '@kbn/securitysolution-io-ts-list-types'; - -import { euiThemeVars } from '@kbn/ui-theme'; -import { EmptyViewerState, ExceptionItemCard, Pagination, PaginationProps } from '../..'; - -import type { - RuleReferences, - ExceptionListItemIdentifiers, - ViewerStatus, - GetExceptionItemProps, -} from '../types'; - -const exceptionItemCss = css` - margin: ${euiThemeVars.euiSize} 0; - &div:first-child { - margin: ${euiThemeVars.euiSizeXS} 0 ${euiThemeVars.euiSize}; - } -`; - -interface ExceptionItemsProps { - lastUpdated: string | number | null; - viewerStatus: ViewerStatus; - isReadOnly: boolean; - emptyViewerTitle?: string; - emptyViewerBody?: string; - emptyViewerButtonText?: string; - exceptions: ExceptionListItemSchema[]; - listType: ExceptionListTypeEnum; - ruleReferences: RuleReferences; - pagination: PaginationProps['pagination']; - editActionLabel?: string; - deleteActionLabel?: string; - dataTestSubj?: string; - securityLinkAnchorComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - formattedDateComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - exceptionsUtilityComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - getFormattedComments: (comments: CommentsArray) => EuiCommentProps[]; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - onCreateExceptionListItem?: () => void; - onDeleteException: (arg: ExceptionListItemIdentifiers) => void; - onEditExceptionItem: (item: ExceptionListItemSchema) => void; - onPaginationChange: (arg: GetExceptionItemProps) => void; - showValueListModal: ElementType; -} - -const ExceptionItemsComponent: FC = ({ - lastUpdated, - viewerStatus, - isReadOnly, - exceptions, - listType, - ruleReferences, - emptyViewerTitle, - emptyViewerBody, - emptyViewerButtonText, - pagination, - dataTestSubj, - editActionLabel, - deleteActionLabel, - securityLinkAnchorComponent, - exceptionsUtilityComponent, - formattedDateComponent, - getFormattedComments, - onPaginationChange, - onDeleteException, - onEditExceptionItem, - onCreateExceptionListItem, - showValueListModal, -}) => { - const ExceptionsUtility = exceptionsUtilityComponent; - if (!exceptions.length || viewerStatus) - return ( - - ); - const ShowValueListModal = showValueListModal; - return ( - <> - - - - - {exceptions.map((exception) => ( - - - - ))} - - - - - - ); -}; - -ExceptionItemsComponent.displayName = 'ExceptionItemsComponent'; - -export const ExceptionItems = React.memo(ExceptionItemsComponent); - -ExceptionItems.displayName = 'ExceptionsItems'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/index.tsx deleted file mode 100644 index d68ac8f114a09..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/index.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { ElementType, ReactElement } from 'react'; -import { EuiContextMenuItem, EuiFlexGroup, EuiFlexItem, EuiIcon, IconType } from '@elastic/eui'; -import { Rule } from '../types'; -import { itemContentCss, containerCss } from './menu_link.styles'; - -interface MenuItemLinkedRulesProps { - leftIcon?: IconType; - dataTestSubj?: string; - linkedRules: Rule[]; - securityLinkAnchorComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common -} - -export const generateLinkedRulesMenuItems = ({ - dataTestSubj, - linkedRules, - securityLinkAnchorComponent, - leftIcon = '', -}: MenuItemLinkedRulesProps): ReactElement[] | null => { - if (!linkedRules.length || securityLinkAnchorComponent === null) return null; - - const SecurityLinkAnchor = securityLinkAnchorComponent; - return linkedRules.map((rule) => { - return ( - 1 ? containerCss : ''} - data-test-subj={`${dataTestSubj || ''}ActionItem${rule.id}`} - key={rule.id} - > - - {leftIcon ? ( - - - - ) : null} - - - - - - ); - }); -}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/menu_link.styles.ts b/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/menu_link.styles.ts deleted file mode 100644 index 42f470ce39dd5..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/menu_link.styles.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { css } from '@emotion/react'; -import { euiThemeVars } from '@kbn/ui-theme'; - -export const containerCss = css` - border-bottom: 1px solid ${euiThemeVars.euiColorLightShade}; -`; - -export const itemContentCss = css` - color: ${euiThemeVars.euiColorPrimary}; - flex-basis: content; -`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx deleted file mode 100644 index 2f39959c33fe4..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { FC, ReactElement, useMemo, useState } from 'react'; -import { - EuiButtonEmpty, - EuiButtonEmptyProps, - EuiButtonIcon, - EuiContextMenuItem, - EuiContextMenuPanel, - EuiFlexGroup, - EuiPopover, - PanelPaddingSize, - PopoverAnchorPosition, -} from '@elastic/eui'; - -import { css } from '@emotion/react'; - -export interface Action { - key: string; - icon: string; - label: string | boolean; - disabled?: boolean; - onClick: (e: React.MouseEvent) => void; -} - -interface HeaderMenuComponentProps { - disableActions: boolean; - actions: Action[] | ReactElement[] | null; - text?: string; - iconType?: EuiButtonEmptyProps['iconType']; - iconSide?: EuiButtonEmptyProps['iconSide']; - dataTestSubj?: string; - emptyButton?: boolean; - useCustomActions?: boolean; - anchorPosition?: PopoverAnchorPosition; - panelPaddingSize?: PanelPaddingSize; -} - -const popoverHeightStyle = css` - max-height: 300px; - height: 100%; - overflow-x: hidden; - overflow-y: auto; -`; -const HeaderMenuComponent: FC = ({ - text, - dataTestSubj, - actions, - disableActions, - emptyButton, - useCustomActions, - iconType, - iconSide = 'left', - anchorPosition = 'downCenter', - panelPaddingSize = 's', -}) => { - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - - const onAffectedRulesClick = () => setIsPopoverOpen((isOpen) => !isOpen); - const onClosePopover = () => setIsPopoverOpen(false); - - const itemActions = useMemo(() => { - if (useCustomActions || actions === null) return actions; - return (actions as Action[]).map((action) => ( - { - onClosePopover(); - if (typeof action.onClick === 'function') action.onClick(e); - }} - > - {action.label} - - )); - }, [actions, dataTestSubj, useCustomActions]); - - return ( - - - {text} - - ) : ( - - {text} - - ) - } - onClick={(e) => e.stopPropagation()} - panelPaddingSize={panelPaddingSize} - isOpen={isPopoverOpen} - closePopover={onClosePopover} - anchorPosition={anchorPosition} - data-test-subj={`${dataTestSubj || ''}Items`} - > - {!itemActions ? null : ( - - )} - - - ); -}; -HeaderMenuComponent.displayName = 'HeaderMenuComponent'; - -export const HeaderMenu = React.memo(HeaderMenuComponent); - -HeaderMenu.displayName = 'HeaderMenu'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/index.tsx deleted file mode 100644 index 82aec99bebb3a..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/index.tsx +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { FC } from 'react'; -import { - EuiButton, - EuiButtonEmpty, - EuiFieldText, - EuiForm, - EuiFormRow, - EuiModal, - EuiModalBody, - EuiModalFooter, - EuiModalHeader, - EuiModalHeaderTitle, - EuiTextArea, - EuiProgress, -} from '@elastic/eui'; -import * as i18n from '../../translations'; -import { ListDetails } from '../../types'; -import { useEditModal } from './use_edit_modal'; - -interface EditModalProps { - listDetails: ListDetails; - onSave: (newListDetails: ListDetails) => void; - onCancel: () => void; -} - -const EditModalComponent: FC = ({ listDetails, onSave, onCancel }) => { - const { error, modalFormId, newListDetails, showProgress, onBlur, onSubmit, onChange } = - useEditModal({ - listDetails, - onSave, - }); - return ( - - {showProgress && ( - - )} - - - {i18n.EXCEPTION_LIST_HEADER_EDIT_MODAL_TITLE(listDetails.name)} - - - - - - - - - - - - - - - - - - {i18n.EXCEPTION_LIST_HEADER_EDIT_MODAL_CANCEL_BUTTON} - - - - {i18n.EXCEPTION_LIST_HEADER_EDIT_MODAL_SAVE_BUTTON} - - - - ); -}; -EditModalComponent.displayName = 'EditModalComponent'; - -export const EditModal = React.memo(EditModalComponent); - -EditModal.displayName = 'EditModal'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx deleted file mode 100644 index 849dd4ef1ba85..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import type { FC } from 'react'; -import { EuiIcon, EuiPageHeader, EuiText } from '@elastic/eui'; -import * as i18n from '../translations'; -import { textCss, descriptionContainerCss, backTextCss } from './list_header.styles'; -import { MenuItems } from './menu_items'; -import { TextWithEdit } from '../text_with_edit'; -import { EditModal } from './edit_modal'; -import { ListDetails, Rule } from '../types'; -import { useExceptionListHeader } from './use_list_header'; -import { textWithEditContainerCss } from '../text_with_edit/text_with_edit.styles'; - -interface ExceptionListHeaderComponentProps { - name: string; - description?: string; - listId: string; - isReadonly: boolean; - linkedRules: Rule[]; - dataTestSubj?: string; - backOptions: BackOptions; - canUserEditList?: boolean; - securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - onEditListDetails: (listDetails: ListDetails) => void; - onDeleteList: () => void; - onManageRules: () => void; - onExportList: () => void; - onDuplicateList: () => void; -} - -export interface BackOptions { - pageId: string; - path: string; - dataTestSubj?: string; - onNavigate: (path: string) => void; -} -const ExceptionListHeaderComponent: FC = ({ - name, - description, - listId, - linkedRules, - isReadonly, - dataTestSubj, - securityLinkAnchorComponent, - backOptions, - canUserEditList = true, - onEditListDetails, - onDeleteList, - onManageRules, - onExportList, - onDuplicateList, -}) => { - const { isModalVisible, listDetails, onEdit, onSave, onCancel } = useExceptionListHeader({ - name, - description, - onEditListDetails, - }); - return ( -
- - } - responsive - data-test-subj={`${dataTestSubj || ''}PageHeader`} - description={ -
- -
- {i18n.EXCEPTION_LIST_HEADER_LIST_ID}: - {listId} -
-
- } - rightSideItems={[ - , - ]} - breadcrumbs={[ - { - text: ( -
- - {i18n.EXCEPTION_LIST_HEADER_BREADCRUMB} -
- ), - color: 'primary', - 'aria-current': false, - href: backOptions.path, - onClick: (e) => { - e.preventDefault(); - backOptions.onNavigate(backOptions.path); - }, - }, - ]} - /> - {isModalVisible && ( - - )} -
- ); -}; - -ExceptionListHeaderComponent.displayName = 'ExceptionListHeaderComponent'; - -export const ExceptionListHeader = React.memo(ExceptionListHeaderComponent); - -ExceptionListHeader.displayName = 'ExceptionListHeader'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.styles.ts b/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.styles.ts deleted file mode 100644 index c3cba9f9dcdbe..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.styles.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { css } from '@emotion/react'; -import { euiThemeVars } from '@kbn/ui-theme'; - -export const headerMenuCss = css` - border-right: 1px solid #d3dae6; - padding: ${euiThemeVars.euiSizeXS} ${euiThemeVars.euiSizeL} ${euiThemeVars.euiSizeXS} 0; -`; - -export const noLinkedRulesCss = css` - width: max-content; -`; - -export const textCss = css` - font-size: ${euiThemeVars.euiFontSize}; - color: ${euiThemeVars.euiTextSubduedColor}; - margin-left: ${euiThemeVars.euiSizeXS}; -`; -export const descriptionContainerCss = css` - margin-top: -${euiThemeVars.euiSizeL}; - margin-bottom: -${euiThemeVars.euiSizeL}; -`; - -export const backTextCss = css` - font-size: ${euiThemeVars.euiFontSizeXS}; -`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/index.tsx deleted file mode 100644 index f0aecf21b6c73..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/index.tsx +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiTextColor } from '@elastic/eui'; -import React, { FC, useMemo } from 'react'; -import { HeaderMenu } from '../../header_menu'; -import { headerMenuCss, noLinkedRulesCss } from '../list_header.styles'; -import * as i18n from '../../translations'; -import { Rule } from '../../types'; -import { generateLinkedRulesMenuItems } from '../../generate_linked_rules_menu_item'; -interface MenuItemsProps { - isReadonly: boolean; - dataTestSubj?: string; - linkedRules: Rule[]; - canUserEditList?: boolean; - securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common - onDeleteList: () => void; - onManageRules: () => void; - onExportList: () => void; - onDuplicateList: () => void; -} - -const MenuItemsComponent: FC = ({ - dataTestSubj, - linkedRules, - securityLinkAnchorComponent, - isReadonly, - canUserEditList = true, - onDeleteList, - onManageRules, - onExportList, - onDuplicateList, -}) => { - const referencedLinks = useMemo( - () => - generateLinkedRulesMenuItems({ - leftIcon: 'check', - dataTestSubj, - linkedRules, - securityLinkAnchorComponent, - }), - [dataTestSubj, linkedRules, securityLinkAnchorComponent] - ); - return ( - - - {linkedRules.length ? ( - - ) : ( - - {i18n.EXCEPTION_LIST_HEADER_LINKED_RULES(linkedRules.length)} - - )} - - - {canUserEditList && ( - - { - if (typeof onManageRules === 'function') onManageRules(); - }} - > - {i18n.EXCEPTION_LIST_HEADER_LINK_RULES_BUTTON} - - - )} - - { - if (typeof onExportList === 'function') onExportList(); - }, - }, - { - key: '2', - icon: 'copy', - label: i18n.EXCEPTION_LIST_HEADER_DUPLICATE_ACTION, - onClick: () => { - if (typeof onDuplicateList === 'function') onDuplicateList(); - }, - disabled: !canUserEditList, - }, - { - key: '3', - icon: 'trash', - label: i18n.EXCEPTION_LIST_HEADER_DELETE_ACTION, - onClick: () => { - if (typeof onDeleteList === 'function') onDeleteList(); - }, - disabled: !canUserEditList, - }, - ]} - disableActions={isReadonly} - anchorPosition="downCenter" - /> - - - ); -}; - -MenuItemsComponent.displayName = 'MenuItemsComponent'; - -export const MenuItems = React.memo(MenuItemsComponent); - -MenuItems.displayName = 'MenuItems'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.ts b/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.ts deleted file mode 100644 index 676dd08a53be1..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useState } from 'react'; -import { ListDetails } from '../types'; - -interface UseExceptionListHeaderProps { - name: string; - description?: string; - onEditListDetails: (listDetails: ListDetails) => void; -} -export const useExceptionListHeader = ({ - name, - description, - onEditListDetails, -}: UseExceptionListHeaderProps) => { - const [isModalVisible, setIsModalVisible] = useState(false); - const [listDetails, setListDetails] = useState({ name, description }); - const onEdit = () => { - setIsModalVisible(true); - }; - const onSave = (newListDetails: ListDetails) => { - setListDetails(newListDetails); - if (typeof onEditListDetails === 'function') onEditListDetails(newListDetails); - setTimeout(() => { - setIsModalVisible(false); - }, 200); - }; - const onCancel = () => { - setIsModalVisible(false); - }; - - return { - isModalVisible, - listDetails, - onEdit, - onSave, - onCancel, - }; -}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/comments.mock.tsx b/packages/kbn-securitysolution-exception-list-components/src/mocks/comments.mock.tsx deleted file mode 100644 index 4c9b813463ca3..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/mocks/comments.mock.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import type { Comment, CommentsArray } from '@kbn/securitysolution-io-ts-list-types'; - -export const getCommentsMock = (): Comment => ({ - comment: 'some old comment', - created_at: '2020-04-20T15:25:31.830Z', - created_by: 'some user', - id: 'uuid_here', -}); - -export const getCommentsArrayMock = (): CommentsArray => [getCommentsMock(), getCommentsMock()]; - -export const mockGetFormattedComments = () => - getCommentsArrayMock().map((comment) => ({ - username: comment.created_by, - children:

{comment.comment}

, - })); diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/entry.mock.ts b/packages/kbn-securitysolution-exception-list-components/src/mocks/entry.mock.ts deleted file mode 100644 index a39fe947caa2e..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/mocks/entry.mock.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { Entry } from '../exception_item_card/conditions/types'; - -export const includedListTypeEntry: Entry = { - field: '', - operator: 'included', - type: 'list', - list: { id: 'list_id', type: 'boolean' }, -}; - -export const includedMatchTypeEntry: Entry = { - field: '', - operator: 'included', - type: 'match', - value: 'matches value', -}; - -export const includedExistsTypeEntry: Entry = { - field: '', - operator: 'included', - type: 'exists', -}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/exception_list_item_schema.mock.ts b/packages/kbn-securitysolution-exception-list-components/src/mocks/exception_list_item_schema.mock.ts deleted file mode 100644 index f9c24d46228c5..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/mocks/exception_list_item_schema.mock.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export const getExceptionListItemSchemaMock = ( - overrides?: Partial -): ExceptionListItemSchema => ({ - _version: undefined, - comments: [], - created_at: '2020-04-20T15:25:31.830Z', - created_by: 'some user', - description: 'some description', - entries: [ - { - entries: [ - { field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }, - ], - field: 'some.parentField', - type: 'nested', - }, - { field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' }, - ], - expire_time: undefined, - id: '1', - item_id: 'endpoint_list_item', - list_id: 'endpoint_list_id', - meta: {}, - name: 'some name', - namespace_type: 'single', - os_types: [], - tags: ['user added string for a tag', 'malware'], - tie_breaker_id: '6a76b69d-80df-4ab2-8c3e-85f466b06a0e', - type: 'simple', - updated_at: '2020-04-20T15:25:31.830Z', - updated_by: 'some user', - ...(overrides || {}), -}); diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/header.mock.ts b/packages/kbn-securitysolution-exception-list-components/src/mocks/header.mock.ts deleted file mode 100644 index 06aa00b5ff724..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/mocks/header.mock.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export const handleEdit = jest.fn(); -export const handleDelete = jest.fn(); -export const actions = [ - { - key: 'edit', - icon: 'pencil', - label: 'Edit detection exception', - onClick: handleEdit, - }, - { - key: 'delete', - icon: 'trash', - label: 'Delete detection exception', - onClick: handleDelete, - }, -]; -export const actionsWithDisabledDelete = [ - { - key: 'edit', - icon: 'pencil', - label: 'Edit detection exception', - onClick: handleEdit, - }, - { - key: 'delete', - icon: 'trash', - disabled: true, - label: 'Delete detection exception', - onClick: handleDelete, - }, -]; diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/rule_references.mock.ts b/packages/kbn-securitysolution-exception-list-components/src/mocks/rule_references.mock.ts deleted file mode 100644 index 3592d5f03cc4c..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/mocks/rule_references.mock.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { Rule, RuleReference } from '../types'; - -export const rules: Rule[] = [ - { - exceptions_list: [ - { - id: '123', - list_id: 'i_exist', - namespace_type: 'single', - type: 'detection', - }, - { - id: '456', - list_id: 'i_exist_2', - namespace_type: 'single', - type: 'detection', - }, - ], - id: '1a2b3c', - name: 'Simple Rule Query', - rule_id: 'rule-2', - }, -]; - -export const ruleReference: RuleReference = { - name: 'endpoint list', - id: 'endpoint_list', - referenced_rules: rules, - listId: 'endpoint_list_id', -}; - -export const ruleReferences = { - endpoint_list_id: ruleReference, -}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/security_link_component.mock.tsx b/packages/kbn-securitysolution-exception-list-components/src/mocks/security_link_component.mock.tsx deleted file mode 100644 index 1ad7d2921c5a0..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/mocks/security_link_component.mock.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { ReactElement } from 'react'; -import { generateLinkedRulesMenuItems } from '../generate_linked_rules_menu_item'; -import { rules } from './rule_references.mock'; -export const securityLinkAnchorComponentMock = ({ - referenceName, - referenceId, -}: { - referenceName: string; - referenceId: string; -}) => ( - -); - -export const getSecurityLinkAction = (dataTestSubj: string) => - generateLinkedRulesMenuItems({ - dataTestSubj, - linkedRules: [ - ...rules, - { - exceptions_list: [], - id: '2a2b3c', - name: 'Simple Rule Query 2', - rule_id: 'rule-2', - }, - ], - securityLinkAnchorComponent: securityLinkAnchorComponentMock, - }) as ReactElement[]; diff --git a/packages/kbn-securitysolution-exception-list-components/src/mocks/value_list_modal.mock.tsx b/packages/kbn-securitysolution-exception-list-components/src/mocks/value_list_modal.mock.tsx deleted file mode 100644 index 930439b577fff..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/mocks/value_list_modal.mock.tsx +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; - -export const mockShowValueListModal = jest.fn(); -export const MockedShowValueListModal = (props: { children: React.ReactNode }) => { - mockShowValueListModal(props); - return <>{props.children}; -}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.tsx b/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.tsx deleted file mode 100644 index 38be3b8474ad7..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import type { FC } from 'react'; -import { EuiTablePagination } from '@elastic/eui'; - -import type { PaginationProps } from '../types'; -import { usePagination } from './use_pagination'; - -const PaginationComponent: FC = ({ - dataTestSubj, - ariaLabel, - pagination, - onPaginationChange, -}) => { - const { - pageIndex, - pageCount, - pageSize, - pageSizeOptions, - - handleItemsPerPageChange, - handlePageIndexChange, - } = usePagination({ pagination, onPaginationChange }); - - return ( - - ); -}; - -PaginationComponent.displayName = 'PaginationComponent'; - -export const Pagination = React.memo(PaginationComponent); - -Pagination.displayName = 'Pagination'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/partial_code_signature_callout/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/partial_code_signature_callout/index.tsx deleted file mode 100644 index 72836fc78fb55..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/partial_code_signature_callout/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; - -import { EuiCallOut } from '@elastic/eui'; - -export const PartialCodeSignatureCallout = () => { - return ( - - - - ); -}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx deleted file mode 100644 index 0670a2553a696..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { useCallback } from 'react'; -import type { FC } from 'react'; - -import type { EuiSearchBarProps, IconType, SearchFilterConfig } from '@elastic/eui'; -import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiSearchBar } from '@elastic/eui'; -import type { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import type { GetExceptionItemProps } from '../types'; - -const ITEMS_SCHEMA = { - strict: true, - fields: { - created_by: { - type: 'string', - }, - description: { - type: 'string', - }, - id: { - type: 'string', - }, - item_id: { - type: 'string', - }, - list_id: { - type: 'string', - }, - name: { - type: 'string', - }, - os_types: { - type: 'string', - }, - tags: { - type: 'string', - }, - }, -}; -interface SearchBarProps { - addExceptionButtonText?: string; - placeholdertext?: string; - canAddException?: boolean; // TODO what is the default value - - // TODO: REFACTOR: not to send the listType and handle it in the Parent - // Exception list type used to determine what type of item is - // being created when "onAddExceptionClick" is invoked - listType: ExceptionListTypeEnum; - isSearching?: boolean; - dataTestSubj?: string; - filters?: SearchFilterConfig[]; // TODO about filters - isButtonFilled?: boolean; - buttonIconType?: IconType; - onSearch: (arg: GetExceptionItemProps) => void; - onAddExceptionClick: (type: ExceptionListTypeEnum) => void; -} -const SearchBarComponent: FC = ({ - addExceptionButtonText, - placeholdertext, - canAddException, - listType, - isSearching, - dataTestSubj, - filters = [], - isButtonFilled = true, - buttonIconType, - onSearch, - onAddExceptionClick, -}) => { - const handleOnSearch = useCallback>( - ({ queryText }): void => { - onSearch({ search: queryText }); - }, - [onSearch] - ); - - const handleAddException = useCallback(() => { - // TODO: ASK YARA why we need to send the listType - onAddExceptionClick(listType); - }, [onAddExceptionClick, listType]); - - return ( - - - - - {!canAddException && ( - - - {addExceptionButtonText} - - - )} - - ); -}; - -SearchBarComponent.displayName = 'SearchBarComponent'; - -export const SearchBar = React.memo(SearchBarComponent); - -SearchBar.displayName = 'SearchBar'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/index.tsx deleted file mode 100644 index aa5625cfe671c..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { FC } from 'react'; -import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { Interpolation, Theme } from '@emotion/react'; -import { textWithEditContainerCss, editIconCss } from './text_with_edit.styles'; -interface TextWithEditProps { - isReadonly: boolean; - dataTestSubj?: string; - text: string; - textCss?: Interpolation; - onEdit?: () => void; -} - -const TextWithEditComponent: FC = ({ - isReadonly, - dataTestSubj, - text, - onEdit, - textCss, -}) => { - return ( - - - - {text} - - - - {isReadonly ? null : ( - (typeof onEdit === 'function' ? onEdit() : null)} - /> - )} - - - ); -}; -TextWithEditComponent.displayName = 'TextWithEditComponent'; - -export const TextWithEdit = React.memo(TextWithEditComponent); - -TextWithEdit.displayName = 'TextWithEdit'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.styles.ts b/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.styles.ts deleted file mode 100644 index e293ea0730410..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.styles.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { css } from '@emotion/react'; -import { euiThemeVars } from '@kbn/ui-theme'; - -export const textWithEditContainerCss = css` - display: flex; - width: fit-content; - align-items: baseline; - padding-bottom: ${euiThemeVars.euiSizeS}; - h1 { - margin-bottom: 0; - } -`; -export const editIconCss = css` - button { - margin-left: -${euiThemeVars.euiSizeM}; - } -`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/translations.ts b/packages/kbn-securitysolution-exception-list-components/src/translations.ts deleted file mode 100644 index dff688d156da8..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/translations.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { i18n } from '@kbn/i18n'; - -export const EMPTY_VIEWER_STATE_EMPTY_TITLE = i18n.translate( - 'exceptionList-components.empty.viewer.state.empty.title', - { - defaultMessage: 'Add exceptions to this list', - } -); - -export const EMPTY_VIEWER_STATE_EMPTY_BODY = i18n.translate( - 'exceptionList-components.empty.viewer.state.empty.body', - { - defaultMessage: 'There is no exception in your list. Create your first exception.', - } -); -export const EMPTY_VIEWER_STATE_EMPTY_SEARCH_TITLE = i18n.translate( - 'exceptionList-components.empty.viewer.state.empty_search.search.title', - { - defaultMessage: 'No results match your search criteria', - } -); - -export const EMPTY_VIEWER_STATE_EMPTY_SEARCH_BODY = i18n.translate( - 'exceptionList-components.empty.viewer.state.empty_search.body', - { - defaultMessage: 'Try modifying your search', - } -); - -export const EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON = (exceptionType: string) => - i18n.translate('exceptionList-components.empty.viewer.state.empty.viewer_button', { - values: { exceptionType }, - defaultMessage: 'Create {exceptionType} exception', - }); - -export const EMPTY_VIEWER_STATE_ERROR_TITLE = i18n.translate( - 'exceptionList-components.empty.viewer.state.error_title', - { - defaultMessage: 'Unable to load exception items', - } -); - -export const EMPTY_VIEWER_STATE_ERROR_BODY = i18n.translate( - 'exceptionList-components.empty.viewer.state.error_body', - { - defaultMessage: - 'There was an error loading the exception items. Contact your administrator for help.', - } -); -export const EXCEPTION_LIST_HEADER_EXPORT_ACTION = i18n.translate( - 'exceptionList-components.exception_list_header_export_action', - { - defaultMessage: 'Export exception list', - } -); -export const EXCEPTION_LIST_HEADER_DELETE_ACTION = i18n.translate( - 'exceptionList-components.exception_list_header_delete_action', - { - defaultMessage: 'Delete exception list', - } -); -export const EXCEPTION_LIST_HEADER_DUPLICATE_ACTION = i18n.translate( - 'exceptionList-components.exception_list_header_duplicate_action', - { - defaultMessage: 'Duplicate exception list', - } -); -export const EXCEPTION_LIST_HEADER_LINK_RULES_BUTTON = i18n.translate( - 'exceptionList-components.exception_list_header_link_rules_button', - { - defaultMessage: 'Link rules', - } -); - -export const EXCEPTION_LIST_HEADER_LINKED_RULES = (noOfRules: number) => - i18n.translate('exceptionList-components.exception_list_header_linked_rules', { - values: { noOfRules }, - defaultMessage: 'Linked to {noOfRules} rules', - }); - -export const EXCEPTION_LIST_HEADER_BREADCRUMB = i18n.translate( - 'exceptionList-components.exception_list_header_breadcrumb', - { - defaultMessage: 'Shared Exception Lists', - } -); - -export const EXCEPTION_LIST_HEADER_LIST_ID = i18n.translate( - 'exceptionList-components.exception_list_header_list_id', - { - defaultMessage: 'List ID', - } -); - -export const EXCEPTION_LIST_HEADER_NAME = i18n.translate( - 'exceptionList-components.exception_list_header_name', - { - defaultMessage: 'Add a name', - } -); - -export const EXCEPTION_LIST_HEADER_DESCRIPTION = i18n.translate( - 'exceptionList-components.exception_list_header_description', - { - defaultMessage: 'Add a description', - } -); - -export const EXCEPTION_LIST_HEADER_EDIT_MODAL_TITLE = (listName: string) => - i18n.translate('exceptionList-components.exception_list_header_edit_modal_name', { - defaultMessage: 'Edit {listName}', - values: { listName }, - }); - -export const EXCEPTION_LIST_HEADER_EDIT_MODAL_SAVE_BUTTON = i18n.translate( - 'exceptionList-components.exception_list_header_edit_modal_save_button', - { - defaultMessage: 'Save', - } -); - -export const EXCEPTION_LIST_HEADER_EDIT_MODAL_CANCEL_BUTTON = i18n.translate( - 'exceptionList-components.exception_list_header_edit_modal_cancel_button', - { - defaultMessage: 'Cancel', - } -); -export const EXCEPTION_LIST_HEADER_NAME_TEXTBOX = i18n.translate( - 'exceptionList-components.exception_list_header_Name_textbox', - { - defaultMessage: 'Name', - } -); - -export const EXCEPTION_LIST_HEADER_DESCRIPTION_TEXTBOX = i18n.translate( - 'exceptionList-components.exception_list_header_description_textbox', - { - defaultMessage: 'Description (optional)', - } -); - -export const LIST_NAME_REQUIRED_ERROR = i18n.translate( - 'exceptionList-components.exception_list_header_description_textboxexceptionList-components.exception_list_header_name_required_eror', - { - defaultMessage: 'List name cannot be empty', - } -); diff --git a/packages/kbn-securitysolution-exception-list-components/src/types/index.ts b/packages/kbn-securitysolution-exception-list-components/src/types/index.ts deleted file mode 100644 index 57a0ee3901ba4..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/types/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ListArray } from '@kbn/securitysolution-io-ts-list-types'; - -import type { Pagination } from '@elastic/eui'; -import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; - -export interface GetExceptionItemProps { - pagination?: PaginationProps['pagination']; - search?: string; - filters?: string; -} - -export interface PaginationProps { - dataTestSubj?: string; - ariaLabel?: string; - pagination: Pagination & { pageSize: number }; - onPaginationChange: (arg: GetExceptionItemProps) => void; -} - -export enum ViewerStatus { - ERROR = 'error', - EMPTY = 'empty', - EMPTY_SEARCH = 'empty_search', - LOADING = 'loading', - SEARCHING = 'searching', - DELETING = 'deleting', -} - -export interface ExceptionListSummaryProps { - pagination: Pagination; - // Corresponds to last time exception items were fetched - lastUpdated: string | number | null; -} - -export type ViewerFlyoutName = 'addException' | 'editException' | null; - -export interface RuleReferences { - [key: string]: RuleReference; -} - -export interface ExceptionListItemIdentifiers { - id: string; - name: string; - namespaceType: NamespaceType; -} - -export enum ListTypeText { - ENDPOINT = 'endpoint', - DETECTION = 'empty', - RULE_DEFAULT = 'empty_search', -} -export interface Rule { - name: string; - id: string; - rule_id: string; - exceptions_list?: ListArray; -} - -export interface RuleReference { - name: string; - id: string; - referenced_rules: Rule[]; - listId?: string; -} - -export interface ListDetails { - name: string; - description?: string; -} diff --git a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/index.ts b/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/index.ts deleted file mode 100644 index 5a0843be833f7..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export { ValueWithSpaceWarning } from './value_with_space_warning'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.ts b/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.ts deleted file mode 100644 index d5a6392815a78..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { paramContainsSpace, autoCompletei18n } from '@kbn/securitysolution-autocomplete'; - -interface UseValueWithSpaceWarningResult { - showSpaceWarningIcon: boolean; - warningText: string; -} -interface UseValueWithSpaceWarningProps { - value: string | string[]; - tooltipIconText?: string; -} - -export const useValueWithSpaceWarning = ({ - value, - tooltipIconText, -}: UseValueWithSpaceWarningProps): UseValueWithSpaceWarningResult => { - const showSpaceWarningIcon = Array.isArray(value) - ? value.find(paramContainsSpace) - : paramContainsSpace(value); - - return { - showSpaceWarningIcon: !!showSpaceWarningIcon, - warningText: tooltipIconText || autoCompletei18n.FIELD_SPACE_WARNING, - }; -}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/wildcard_with_wrong_operator_callout/index.tsx b/packages/kbn-securitysolution-exception-list-components/src/wildcard_with_wrong_operator_callout/index.tsx deleted file mode 100644 index d68782b4c17f8..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/src/wildcard_with_wrong_operator_callout/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; - -import { EuiCallOut } from '@elastic/eui'; - -export const WildCardWithWrongOperatorCallout = () => { - return ( - -

- - {i18n.translate( - 'exceptionList-components.wildcardWithWrongOperatorCallout.changeTheOperator', - { defaultMessage: 'Change the operator' } - )} - - ), - matches: ( - - {i18n.translate( - 'exceptionList-components.wildcardWithWrongOperatorCallout.matches', - { defaultMessage: 'matches' } - )} - - ), - }} - /> -

-
- ); -}; diff --git a/packages/kbn-securitysolution-exception-list-components/tsconfig.json b/packages/kbn-securitysolution-exception-list-components/tsconfig.json deleted file mode 100644 index b3df3a2aa208b..0000000000000 --- a/packages/kbn-securitysolution-exception-list-components/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node", - "react", - "@emotion/react/types/css-prop" - ] - }, - "include": [ - "**/*.ts", - "**/*.tsx", - "**/*.d.ts" - ], - "kbn_references": [ - "@kbn/securitysolution-io-ts-list-types", - "@kbn/securitysolution-autocomplete", - "@kbn/ui-theme", - "@kbn/i18n", - "@kbn/i18n-react", - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.gen.ts b/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.gen.ts deleted file mode 100644 index aedd1f5fc5cc6..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.gen.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Create shared exception list API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { - ExceptionListName, - ExceptionListDescription, - ExceptionList, -} from '../model/exception_list_common.gen'; - -export type CreateSharedExceptionListRequestBody = z.infer< - typeof CreateSharedExceptionListRequestBody ->; -export const CreateSharedExceptionListRequestBody = z.object({ - name: ExceptionListName, - description: ExceptionListDescription, -}); -export type CreateSharedExceptionListRequestBodyInput = z.input< - typeof CreateSharedExceptionListRequestBody ->; - -export type CreateSharedExceptionListResponse = z.infer; -export const CreateSharedExceptionListResponse = ExceptionList; diff --git a/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.schema.yaml b/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.schema.yaml deleted file mode 100644 index c4cee089e5836..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.schema.yaml +++ /dev/null @@ -1,68 +0,0 @@ -openapi: 3.0.0 -info: - title: Create shared exception list API endpoint - version: '2023-10-31' -paths: - /api/exceptions/shared: - post: - x-labels: [serverless, ess] - operationId: CreateSharedExceptionList - x-codegen-enabled: true - summary: Create a shared exception list - description: | - An exception list groups exception items and can be associated with detection rules. A shared exception list can apply to multiple detection rules. - > info - > All exception items added to the same list are evaluated using `OR` logic. That is, if any of the items in a list evaluate to `true`, the exception prevents the rule from generating an alert. Likewise, `OR` logic is used for evaluating exceptions when more than one exception list is assigned to a rule. To use the `AND` operator, you can define multiple clauses (`entries`) in a single exception item. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - name: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListName' - description: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListDescription' - required: - - name - - description - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionList' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 409: - description: Exception list already exists response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.schema.yaml b/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.schema.yaml deleted file mode 100644 index 92afc3232efee..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.schema.yaml +++ /dev/null @@ -1,70 +0,0 @@ -openapi: 3.0.0 -info: - title: Delete exception list API endpoint - version: '2023-10-31' -paths: - /api/exception_lists: - delete: - x-labels: [serverless, ess] - operationId: DeleteExceptionList - x-codegen-enabled: true - summary: Delete an exception list - description: Delete an exception list using the `id` or `list_id` field. - parameters: - - name: id - in: query - required: false - description: Either `id` or `list_id` must be specified - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListId' - - name: list_id - in: query - required: false - description: Either `id` or `list_id` must be specified - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' - - name: namespace_type - in: query - required: false - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' - default: single - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionList' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: Exception list not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.schema.yaml b/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.schema.yaml deleted file mode 100644 index 9f57afcd5ab1c..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.schema.yaml +++ /dev/null @@ -1,70 +0,0 @@ -openapi: 3.0.0 -info: - title: Delete exception list item API endpoint - version: '2023-10-31' -paths: - /api/exception_lists/items: - delete: - x-labels: [serverless, ess] - operationId: DeleteExceptionListItem - x-codegen-enabled: true - summary: Delete an exception list item - description: Delete an exception list item using the `id` or `item_id` field. - parameters: - - name: id - in: query - required: false - description: Either `id` or `item_id` must be specified - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemId' - - name: item_id - in: query - required: false - description: Either `id` or `item_id` must be specified - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemHumanId' - - name: namespace_type - in: query - required: false - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' - default: single - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItem' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: Exception list item not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.schema.yaml b/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.schema.yaml deleted file mode 100644 index 758171327ee4c..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.schema.yaml +++ /dev/null @@ -1,71 +0,0 @@ -openapi: 3.0.0 -info: - title: Duplicate exception list API endpoint - version: '2023-10-31' -paths: - /api/exception_lists/_duplicate: - post: - x-labels: [serverless, ess] - operationId: DuplicateExceptionList - x-codegen-enabled: true - summary: Duplicate an exception list - description: Duplicate an existing exception list. - parameters: - - name: list_id - in: query - required: true - description: Exception list's human identifier - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' - - name: namespace_type - in: query - required: true - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' - - name: include_expired_exceptions - in: query - required: true - description: Determines whether to include expired exceptions in the exported list - schema: - type: string - enum: ['true', 'false'] - default: 'true' - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionList' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 405: - description: Exception list to duplicate not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.gen.ts b/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.gen.ts deleted file mode 100644 index 9645b8ac793cb..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.gen.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Export exception list API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { - ExceptionListId, - ExceptionListHumanId, - ExceptionNamespaceType, -} from '../model/exception_list_common.gen'; - -export type ExportExceptionListRequestQuery = z.infer; -export const ExportExceptionListRequestQuery = z.object({ - /** - * Exception list's identifier - */ - id: ExceptionListId, - /** - * Exception list's human identifier - */ - list_id: ExceptionListHumanId, - namespace_type: ExceptionNamespaceType, - /** - * Determines whether to include expired exceptions in the exported list - */ - include_expired_exceptions: z.enum(['true', 'false']).default('true'), -}); -export type ExportExceptionListRequestQueryInput = z.input; diff --git a/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.schema.yaml b/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.schema.yaml deleted file mode 100644 index 3232f46c238c8..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.schema.yaml +++ /dev/null @@ -1,79 +0,0 @@ -openapi: 3.0.0 -info: - title: Export exception list API endpoint - version: '2023-10-31' -paths: - /api/exception_lists/_export: - post: - x-labels: [serverless, ess] - operationId: ExportExceptionList - x-codegen-enabled: true - summary: Export an exception list - description: Export an exception list and its associated items to an NDJSON file. - parameters: - - name: id - in: query - required: true - description: Exception list's identifier - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListId' - - name: list_id - in: query - required: true - description: Exception list's human identifier - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' - - name: namespace_type - in: query - required: true - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' - - name: include_expired_exceptions - in: query - required: true - description: Determines whether to include expired exceptions in the exported list - schema: - type: string - enum: ['true', 'false'] - default: 'true' - responses: - 200: - description: Successful response - content: - application/ndjson: - schema: - type: string - format: binary - description: A `.ndjson` file containing specified exception list and its items - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: Exception list not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/index.ts b/packages/kbn-securitysolution-exceptions-common/api/index.ts deleted file mode 100644 index fd6722b67ace3..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './model/exception_list_common.gen'; -export * from './model/exception_list_item_entry.gen'; -export * from './create_exception_list_item/create_exception_list_item.gen'; -export * from './create_rule_exceptions/create_rule_exceptions.gen'; -export * from './create_shared_exceptions_list/create_shared_exceptions_list.gen'; -export * from './create_exception_list/create_exception_list.gen'; -export * from './delete_exception_list_item/delete_exception_list_item.gen'; -export * from './delete_exception_list/delete_exception_list.gen'; -export * from './duplicate_exception_list/duplicate_exception_list.gen'; -export * from './export_exception_list/export_exception_list.gen'; -export * from './find_exception_list_items/find_exception_list_items.gen'; -export * from './find_exception_lists/find_exception_lists.gen'; -export * from './import_exceptions/import_exceptions.gen'; -export * from './read_exception_list_item/read_exception_list_item.gen'; -export * from './read_exception_list/read_exception_list.gen'; -export * from './read_exception_list_summary/read_exception_list_summary.gen'; -export * from './update_exception_list_item/update_exception_list_item.gen'; -export * from './update_exception_list/update_exception_list.gen'; diff --git a/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.schema.yaml b/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.schema.yaml deleted file mode 100644 index 883a62e5bbec5..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.schema.yaml +++ /dev/null @@ -1,147 +0,0 @@ -openapi: 3.0.0 -info: - title: Common Exception List Item Entry Attributes - version: 'not applicable' -paths: {} -components: - x-codegen-enabled: true - schemas: - ExceptionListItemEntryOperator: - type: string - enum: [excluded, included] - - ExceptionListItemEntryMatch: - type: object - properties: - type: - type: string - enum: [match] - field: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - value: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - operator: - $ref: '#/components/schemas/ExceptionListItemEntryOperator' - required: - - type - - field - - value - - operator - - ExceptionListItemEntryMatchAny: - type: object - properties: - type: - type: string - enum: [match_any] - field: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - value: - type: array - items: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - minItems: 1 - operator: - $ref: '#/components/schemas/ExceptionListItemEntryOperator' - required: - - type - - field - - value - - operator - - ExceptionListItemEntryList: - type: object - properties: - type: - type: string - enum: [list] - field: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - list: - type: object - properties: - id: - $ref: '../../../kbn-securitysolution-lists-common/api/model/list_common.schema.yaml#/components/schemas/ListId' - type: - $ref: '../../../kbn-securitysolution-lists-common/api/model/list_common.schema.yaml#/components/schemas/ListType' - required: [id, type] - operator: - $ref: '#/components/schemas/ExceptionListItemEntryOperator' - required: - - type - - field - - list - - operator - - ExceptionListItemEntryExists: - type: object - properties: - type: - type: string - enum: [exists] - field: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - operator: - $ref: '#/components/schemas/ExceptionListItemEntryOperator' - required: - - type - - field - - operator - - ExceptionListItemEntryNestedEntryItem: - oneOf: - - $ref: '#/components/schemas/ExceptionListItemEntryMatch' - - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' - - $ref: '#/components/schemas/ExceptionListItemEntryExists' - - ExceptionListItemEntryNested: - type: object - properties: - type: - type: string - enum: [nested] - field: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - entries: - type: array - items: - $ref: '#/components/schemas/ExceptionListItemEntryNestedEntryItem' - minItems: 1 - required: - - type - - field - - entries - - ExceptionListItemEntryMatchWildcard: - type: object - properties: - type: - type: string - enum: [wildcard] - field: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - value: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - operator: - $ref: '#/components/schemas/ExceptionListItemEntryOperator' - required: - - type - - field - - value - - operator - - ExceptionListItemEntry: - discriminator: - propertyName: type - anyOf: - - $ref: '#/components/schemas/ExceptionListItemEntryMatch' - - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' - - $ref: '#/components/schemas/ExceptionListItemEntryList' - - $ref: '#/components/schemas/ExceptionListItemEntryExists' - - $ref: '#/components/schemas/ExceptionListItemEntryNested' - - $ref: '#/components/schemas/ExceptionListItemEntryMatchWildcard' - - ExceptionListItemEntryArray: - type: array - items: - $ref: '#/components/schemas/ExceptionListItemEntry' diff --git a/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts b/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts deleted file mode 100644 index 4827baab85e90..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts +++ /dev/null @@ -1,427 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Exceptions API client for quickstart - * version: Bundle (no version) - */ - -import type { KbnClient } from '@kbn/test'; -import { ToolingLog } from '@kbn/tooling-log'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { replaceParams } from '@kbn/openapi-common/shared'; -import { catchAxiosErrorFormatAndThrow } from '@kbn/securitysolution-utils'; - -import type { - CreateExceptionListItemRequestBodyInput, - CreateExceptionListItemResponse, -} from './create_exception_list_item/create_exception_list_item.gen'; -import type { - CreateExceptionListRequestBodyInput, - CreateExceptionListResponse, -} from './create_exception_list/create_exception_list.gen'; -import type { - CreateRuleExceptionListItemsRequestParamsInput, - CreateRuleExceptionListItemsRequestBodyInput, - CreateRuleExceptionListItemsResponse, -} from './create_rule_exceptions/create_rule_exceptions.gen'; -import type { - CreateSharedExceptionListRequestBodyInput, - CreateSharedExceptionListResponse, -} from './create_shared_exceptions_list/create_shared_exceptions_list.gen'; -import type { - DeleteExceptionListItemRequestQueryInput, - DeleteExceptionListItemResponse, -} from './delete_exception_list_item/delete_exception_list_item.gen'; -import type { - DeleteExceptionListRequestQueryInput, - DeleteExceptionListResponse, -} from './delete_exception_list/delete_exception_list.gen'; -import type { - DuplicateExceptionListRequestQueryInput, - DuplicateExceptionListResponse, -} from './duplicate_exception_list/duplicate_exception_list.gen'; -import type { ExportExceptionListRequestQueryInput } from './export_exception_list/export_exception_list.gen'; -import type { - FindExceptionListItemsRequestQueryInput, - FindExceptionListItemsResponse, -} from './find_exception_list_items/find_exception_list_items.gen'; -import type { - FindExceptionListsRequestQueryInput, - FindExceptionListsResponse, -} from './find_exception_lists/find_exception_lists.gen'; -import type { - ImportExceptionListRequestQueryInput, - ImportExceptionListResponse, -} from './import_exceptions/import_exceptions.gen'; -import type { - ReadExceptionListItemRequestQueryInput, - ReadExceptionListItemResponse, -} from './read_exception_list_item/read_exception_list_item.gen'; -import type { - ReadExceptionListSummaryRequestQueryInput, - ReadExceptionListSummaryResponse, -} from './read_exception_list_summary/read_exception_list_summary.gen'; -import type { - ReadExceptionListRequestQueryInput, - ReadExceptionListResponse, -} from './read_exception_list/read_exception_list.gen'; -import type { - UpdateExceptionListItemRequestBodyInput, - UpdateExceptionListItemResponse, -} from './update_exception_list_item/update_exception_list_item.gen'; -import type { - UpdateExceptionListRequestBodyInput, - UpdateExceptionListResponse, -} from './update_exception_list/update_exception_list.gen'; - -export interface ClientOptions { - kbnClient: KbnClient; - log: ToolingLog; -} - -export class Client { - readonly kbnClient: KbnClient; - readonly log: ToolingLog; - - constructor(options: ClientOptions) { - this.kbnClient = options.kbnClient; - this.log = options.log; - } - /** - * An exception list groups exception items and can be associated with detection rules. You can assign detection rules with multiple exception lists. -> info -> All exception items added to the same list are evaluated using `OR` logic. That is, if any of the items in a list evaluate to `true`, the exception prevents the rule from generating an alert. Likewise, `OR` logic is used for evaluating exceptions when more than one exception list is assigned to a rule. To use the `AND` operator, you can define multiple clauses (`entries`) in a single exception item. - - */ - async createExceptionList(props: CreateExceptionListProps) { - this.log.info(`${new Date().toISOString()} Calling API CreateExceptionList`); - return this.kbnClient - .request({ - path: '/api/exception_lists', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Create an exception item and associate it with the specified exception list. -> info -> Before creating exception items, you must create an exception list. - - */ - async createExceptionListItem(props: CreateExceptionListItemProps) { - this.log.info(`${new Date().toISOString()} Calling API CreateExceptionListItem`); - return this.kbnClient - .request({ - path: '/api/exception_lists/items', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Create exception items that apply to a single detection rule. - */ - async createRuleExceptionListItems(props: CreateRuleExceptionListItemsProps) { - this.log.info(`${new Date().toISOString()} Calling API CreateRuleExceptionListItems`); - return this.kbnClient - .request({ - path: replaceParams('/api/detection_engine/rules/{id}/exceptions', props.params), - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * An exception list groups exception items and can be associated with detection rules. A shared exception list can apply to multiple detection rules. -> info -> All exception items added to the same list are evaluated using `OR` logic. That is, if any of the items in a list evaluate to `true`, the exception prevents the rule from generating an alert. Likewise, `OR` logic is used for evaluating exceptions when more than one exception list is assigned to a rule. To use the `AND` operator, you can define multiple clauses (`entries`) in a single exception item. - - */ - async createSharedExceptionList(props: CreateSharedExceptionListProps) { - this.log.info(`${new Date().toISOString()} Calling API CreateSharedExceptionList`); - return this.kbnClient - .request({ - path: '/api/exceptions/shared', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Delete an exception list using the `id` or `list_id` field. - */ - async deleteExceptionList(props: DeleteExceptionListProps) { - this.log.info(`${new Date().toISOString()} Calling API DeleteExceptionList`); - return this.kbnClient - .request({ - path: '/api/exception_lists', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'DELETE', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Delete an exception list item using the `id` or `item_id` field. - */ - async deleteExceptionListItem(props: DeleteExceptionListItemProps) { - this.log.info(`${new Date().toISOString()} Calling API DeleteExceptionListItem`); - return this.kbnClient - .request({ - path: '/api/exception_lists/items', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'DELETE', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Duplicate an existing exception list. - */ - async duplicateExceptionList(props: DuplicateExceptionListProps) { - this.log.info(`${new Date().toISOString()} Calling API DuplicateExceptionList`); - return this.kbnClient - .request({ - path: '/api/exception_lists/_duplicate', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Export an exception list and its associated items to an NDJSON file. - */ - async exportExceptionList(props: ExportExceptionListProps) { - this.log.info(`${new Date().toISOString()} Calling API ExportExceptionList`); - return this.kbnClient - .request({ - path: '/api/exception_lists/_export', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Get a list of all exception list items in the specified list. - */ - async findExceptionListItems(props: FindExceptionListItemsProps) { - this.log.info(`${new Date().toISOString()} Calling API FindExceptionListItems`); - return this.kbnClient - .request({ - path: '/api/exception_lists/items/_find', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Get a list of all exception lists. - */ - async findExceptionLists(props: FindExceptionListsProps) { - this.log.info(`${new Date().toISOString()} Calling API FindExceptionLists`); - return this.kbnClient - .request({ - path: '/api/exception_lists/_find', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Import an exception list and its associated items from an NDJSON file. - */ - async importExceptionList(props: ImportExceptionListProps) { - this.log.info(`${new Date().toISOString()} Calling API ImportExceptionList`); - return this.kbnClient - .request({ - path: '/api/exception_lists/_import', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - body: props.attachment, - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Get the details of an exception list using the `id` or `list_id` field. - */ - async readExceptionList(props: ReadExceptionListProps) { - this.log.info(`${new Date().toISOString()} Calling API ReadExceptionList`); - return this.kbnClient - .request({ - path: '/api/exception_lists', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Get the details of an exception list item using the `id` or `item_id` field. - */ - async readExceptionListItem(props: ReadExceptionListItemProps) { - this.log.info(`${new Date().toISOString()} Calling API ReadExceptionListItem`); - return this.kbnClient - .request({ - path: '/api/exception_lists/items', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Get a summary of the specified exception list. - */ - async readExceptionListSummary(props: ReadExceptionListSummaryProps) { - this.log.info(`${new Date().toISOString()} Calling API ReadExceptionListSummary`); - return this.kbnClient - .request({ - path: '/api/exception_lists/summary', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Update an exception list using the `id` or `list_id` field. - */ - async updateExceptionList(props: UpdateExceptionListProps) { - this.log.info(`${new Date().toISOString()} Calling API UpdateExceptionList`); - return this.kbnClient - .request({ - path: '/api/exception_lists', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'PUT', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Update an exception list item using the `id` or `item_id` field. - */ - async updateExceptionListItem(props: UpdateExceptionListItemProps) { - this.log.info(`${new Date().toISOString()} Calling API UpdateExceptionListItem`); - return this.kbnClient - .request({ - path: '/api/exception_lists/items', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'PUT', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } -} - -export interface CreateExceptionListProps { - body: CreateExceptionListRequestBodyInput; -} -export interface CreateExceptionListItemProps { - body: CreateExceptionListItemRequestBodyInput; -} -export interface CreateRuleExceptionListItemsProps { - params: CreateRuleExceptionListItemsRequestParamsInput; - body: CreateRuleExceptionListItemsRequestBodyInput; -} -export interface CreateSharedExceptionListProps { - body: CreateSharedExceptionListRequestBodyInput; -} -export interface DeleteExceptionListProps { - query: DeleteExceptionListRequestQueryInput; -} -export interface DeleteExceptionListItemProps { - query: DeleteExceptionListItemRequestQueryInput; -} -export interface DuplicateExceptionListProps { - query: DuplicateExceptionListRequestQueryInput; -} -export interface ExportExceptionListProps { - query: ExportExceptionListRequestQueryInput; -} -export interface FindExceptionListItemsProps { - query: FindExceptionListItemsRequestQueryInput; -} -export interface FindExceptionListsProps { - query: FindExceptionListsRequestQueryInput; -} -export interface ImportExceptionListProps { - query: ImportExceptionListRequestQueryInput; - attachment: FormData; -} -export interface ReadExceptionListProps { - query: ReadExceptionListRequestQueryInput; -} -export interface ReadExceptionListItemProps { - query: ReadExceptionListItemRequestQueryInput; -} -export interface ReadExceptionListSummaryProps { - query: ReadExceptionListSummaryRequestQueryInput; -} -export interface UpdateExceptionListProps { - body: UpdateExceptionListRequestBodyInput; -} -export interface UpdateExceptionListItemProps { - body: UpdateExceptionListItemRequestBodyInput; -} diff --git a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.gen.ts b/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.gen.ts deleted file mode 100644 index 67a832b01195c..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.gen.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Read exception list API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { - ExceptionListId, - ExceptionListHumanId, - ExceptionNamespaceType, - ExceptionList, -} from '../model/exception_list_common.gen'; - -export type ReadExceptionListRequestQuery = z.infer; -export const ReadExceptionListRequestQuery = z.object({ - /** - * Either `id` or `list_id` must be specified - */ - id: ExceptionListId.optional(), - /** - * Either `id` or `list_id` must be specified - */ - list_id: ExceptionListHumanId.optional(), - namespace_type: ExceptionNamespaceType.optional().default('single'), -}); -export type ReadExceptionListRequestQueryInput = z.input; - -export type ReadExceptionListResponse = z.infer; -export const ReadExceptionListResponse = ExceptionList; diff --git a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.schema.yaml b/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.schema.yaml deleted file mode 100644 index 0bf082c1713bd..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.schema.yaml +++ /dev/null @@ -1,70 +0,0 @@ -openapi: 3.0.0 -info: - title: Read exception list API endpoint - version: '2023-10-31' -paths: - /api/exception_lists: - get: - x-labels: [serverless, ess] - operationId: ReadExceptionList - x-codegen-enabled: true - summary: Get exception list details - description: Get the details of an exception list using the `id` or `list_id` field. - parameters: - - name: id - in: query - required: false - description: Either `id` or `list_id` must be specified - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListId' - - name: list_id - in: query - required: false - description: Either `id` or `list_id` must be specified - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' - - name: namespace_type - in: query - required: false - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' - default: single - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionList' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: Exception list item not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.schema.yaml b/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.schema.yaml deleted file mode 100644 index c271016a87eb5..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.schema.yaml +++ /dev/null @@ -1,70 +0,0 @@ -openapi: 3.0.0 -info: - title: Read exception list item API endpoint - version: '2023-10-31' -paths: - /api/exception_lists/items: - get: - x-labels: [serverless, ess] - operationId: ReadExceptionListItem - x-codegen-enabled: true - summary: Get an exception list item - description: Get the details of an exception list item using the `id` or `item_id` field. - parameters: - - name: id - in: query - required: false - description: Either `id` or `item_id` must be specified - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemId' - - name: item_id - in: query - required: false - description: Either `id` or `item_id` must be specified - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemHumanId' - - name: namespace_type - in: query - required: false - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' - default: single - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItem' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: Exception list item not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.schema.yaml b/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.schema.yaml deleted file mode 100644 index b0627111e877f..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.schema.yaml +++ /dev/null @@ -1,89 +0,0 @@ -openapi: 3.0.0 -info: - title: Read exception list summary API endpoint - version: '2023-10-31' -paths: - /api/exception_lists/summary: - get: - x-labels: [serverless, ess] - operationId: ReadExceptionListSummary - x-codegen-enabled: true - summary: Get an exception list summary - description: Get a summary of the specified exception list. - parameters: - - name: id - in: query - required: false - description: Exception list's identifier generated upon creation - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListId' - - name: list_id - in: query - required: false - description: Exception list's human readable identifier - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' - - name: namespace_type - in: query - required: false - schema: - $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' - default: single - - name: filter - in: query - required: false - description: Search filter clause - schema: - type: string - responses: - 200: - description: Successful response - content: - application/json: - schema: - type: object - properties: - windows: - type: integer - minimum: 0 - linux: - type: integer - minimum: 0 - macos: - type: integer - minimum: 0 - total: - type: integer - minimum: 0 - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: Exception list not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/package.json b/packages/kbn-securitysolution-exceptions-common/package.json deleted file mode 100644 index 5148c4d5eedf5..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "description": "Security Solution Exceptions common package", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "name": "@kbn/securitysolution-exceptions-common", - "private": true, - "version": "1.0.0", - "scripts": { - "openapi:generate": "node scripts/openapi_generate", - "openapi:bundle": "node scripts/openapi_bundle" - } -} diff --git a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js b/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js deleted file mode 100644 index 70299e56eac2e..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -require('../../../src/setup_node_env'); -const { join, resolve } = require('path'); -const { bundle } = require('@kbn/openapi-bundler'); - -const ROOT = resolve(__dirname, '..'); - -(async () => { - await bundle({ - sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), - outputFilePath: join( - ROOT, - 'docs/openapi/serverless/security_solution_exceptions_api_{version}.bundled.schema.yaml' - ), - options: { - includeLabels: ['serverless'], - prototypeDocument: join(ROOT, 'scripts/openapi_bundle_info/exceptions_serverless.info.yaml'), - }, - }); - - await bundle({ - sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), - outputFilePath: join( - ROOT, - 'docs/openapi/ess/security_solution_exceptions_api_{version}.bundled.schema.yaml' - ), - options: { - includeLabels: ['ess'], - prototypeDocument: join(ROOT, 'scripts/openapi_bundle_info/exceptions_ess.info.yaml'), - }, - }); -})(); diff --git a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js b/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js deleted file mode 100644 index 13b260476f3a3..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -require('../../../src/setup_node_env'); -const { join, resolve } = require('path'); -const { generate } = require('@kbn/openapi-generator'); -const { REPO_ROOT } = require('@kbn/repo-info'); - -const ROOT = resolve(__dirname, '..'); - -(async () => { - await generate({ - title: 'OpenAPI Exceptions API Schemas', - rootDir: ROOT, - sourceGlob: './api/**/*.schema.yaml', - templateName: 'zod_operation_schema', - }); - - await generate({ - title: 'Exceptions API client for tests', - rootDir: ROOT, - sourceGlob: './api/**/*.schema.yaml', - templateName: 'api_client_supertest', - skipLinting: true, - bundle: { - outFile: join( - REPO_ROOT, - 'x-pack/test/api_integration/services/security_solution_exceptions_api.gen.ts' - ), - }, - }); - - await generate({ - title: 'Exceptions API client for quickstart', - rootDir: ROOT, - sourceGlob: './api/**/*.schema.yaml', - templateName: 'api_client_quickstart', - skipLinting: true, - bundle: { - outFile: join( - REPO_ROOT, - 'packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts' - ), - }, - }); -})(); diff --git a/packages/kbn-securitysolution-exceptions-common/tsconfig.json b/packages/kbn-securitysolution-exceptions-common/tsconfig.json deleted file mode 100644 index a58753f53a4fb..0000000000000 --- a/packages/kbn-securitysolution-exceptions-common/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "outDir": "target/types", - "types": ["jest", "node"] - }, - "exclude": ["target/**/*"], - "extends": "../../tsconfig.base.json", - "include": ["**/*.ts"], - "kbn_references": [ - "@kbn/openapi-common", - "@kbn/zod-helpers", - "@kbn/securitysolution-lists-common", - "@kbn/test", - "@kbn/tooling-log", - "@kbn/core-http-common", - "@kbn/securitysolution-utils", - "@kbn/zod", - ] -} diff --git a/packages/kbn-securitysolution-hook-utils/index.ts b/packages/kbn-securitysolution-hook-utils/index.ts deleted file mode 100644 index be336bddcf9b5..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './src/types'; -export * from './src/use_async'; -export * from './src/use_is_mounted'; -export * from './src/use_observable'; -export * from './src/with_optional_signal'; diff --git a/packages/kbn-securitysolution-hook-utils/jest.config.js b/packages/kbn-securitysolution-hook-utils/jest.config.js deleted file mode 100644 index badea193370b6..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-hook-utils'], -}; diff --git a/packages/kbn-securitysolution-hook-utils/package.json b/packages/kbn-securitysolution-hook-utils/package.json deleted file mode 100644 index 71a83ce3ebb4b..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@kbn/securitysolution-hook-utils", - "version": "1.0.0", - "description": "Security Solution utilities for React hooks", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true, - "sideEffects": false -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-hook-utils/src/types.ts b/packages/kbn-securitysolution-hook-utils/src/types.ts deleted file mode 100644 index 6642afac7381e..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/src/types.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/** - * Represents the state of an asynchronous task, along with an initiator - * function to kick off the work. - */ -export interface Task { - loading: boolean; - error: unknown | undefined; - result: Result | undefined; - start: (...args: Args) => void; -} diff --git a/packages/kbn-securitysolution-hook-utils/src/use_async/index.test.ts b/packages/kbn-securitysolution-hook-utils/src/use_async/index.test.ts deleted file mode 100644 index 99417c1fe3292..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/src/use_async/index.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { waitFor, renderHook, act } from '@testing-library/react'; - -import { useAsync } from '.'; - -interface TestArgs { - n: number; - s: string; -} - -type TestReturn = Promise; - -describe('useAsync', () => { - /** - * Timeout for both jest tests and for the waitFor. - * jest tests default to 5 seconds and waitFor defaults to 1 second. - * 20_0000 = 20,000 milliseconds = 20 seconds - */ - const timeout = 20_000; - - let fn: jest.Mock; - let args: TestArgs; - - beforeEach(() => { - args = { n: 1, s: 's' }; - fn = jest.fn().mockResolvedValue(false); - }); - - it('does not invoke fn if start was not called', () => { - renderHook(() => useAsync(fn)); - expect(fn).not.toHaveBeenCalled(); - }); - - it( - 'invokes the function when start is called', - async () => { - const { result } = renderHook(() => useAsync(fn)); - - act(() => { - result.current.start(args); - }); - await waitFor(() => expect(fn).toHaveBeenCalled(), { timeout }); - }, - timeout - ); - - it('invokes the function with start args', async () => { - const { result } = renderHook(() => useAsync(fn)); - const expectedArgs = { ...args }; - - act(() => { - result.current.start(args); - }); - await waitFor(() => expect(fn).toHaveBeenCalledWith(expectedArgs), { timeout }); - }); - - it( - 'populates result with the resolved value of the fn', - async () => { - const { result } = renderHook(() => useAsync(fn)); - fn.mockResolvedValue({ resolved: 'value' }); - - act(() => { - result.current.start(args); - }); - await waitFor( - () => { - expect(result.current.result).toEqual({ resolved: 'value' }); - expect(result.current.error).toBeUndefined(); - }, - { timeout } - ); - }, - timeout - ); - - it( - 'populates error if function rejects', - async () => { - fn.mockRejectedValue(new Error('whoops')); - const { result } = renderHook(() => useAsync(fn)); - - act(() => { - result.current.start(args); - }); - - await waitFor( - () => { - expect(result.current.result).toBeUndefined(); - expect(result.current.error).toEqual(new Error('whoops')); - }, - { timeout } - ); - }, - timeout - ); - - it( - 'populates the loading state while the function is pending', - async () => { - let resolve: () => void; - fn.mockImplementation(() => new Promise((_resolve) => (resolve = _resolve))); - - const { result } = renderHook(() => useAsync(fn)); - - act(() => { - result.current.start(args); - }); - - expect(result.current.loading).toBe(true); - - act(() => resolve()); - await waitFor(() => expect(result.current.loading).toBe(false), { timeout }); - }, - timeout - ); - - it( - 'multiple start calls reset state', - async () => { - let resolve: (result: string) => void; - fn.mockImplementation(() => new Promise((_resolve) => (resolve = _resolve))); - - const { result } = renderHook(() => useAsync(fn)); - - act(() => { - result.current.start(args); - }); - - expect(result.current.loading).toBe(true); - - act(() => resolve('result')); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - expect(result.current.result).toBe('result'); - }, - { timeout } - ); - - act(() => { - result.current.start(args); - }); - - expect(result.current.loading).toBe(true); - expect(result.current.result).toBe(undefined); - act(() => resolve('result')); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - expect(result.current.result).toBe('result'); - }, - { timeout } - ); - }, - timeout - ); -}); diff --git a/packages/kbn-securitysolution-hook-utils/src/use_async/index.ts b/packages/kbn-securitysolution-hook-utils/src/use_async/index.ts deleted file mode 100644 index 2c695b26acdd6..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/src/use_async/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useCallback, useState } from 'react'; - -import { Task } from '../types'; -import { useIsMounted } from '../use_is_mounted'; - -/** - * - * This hook wraps a promise-returning thunk (task) in order to conditionally - * initiate the work, and automatically provide state corresponding to the - * task's status. - * - * In order to function properly and not rerender unnecessarily, ensure that - * your task is a stable function reference. - * - * @param fn a function returning a promise. - * - * @returns An {@link Task} containing the task's current state along with a - * start callback - */ -export const useAsync = ( - fn: (...args: Args) => Promise -): Task => { - const isMounted = useIsMounted(); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(); - const [result, setResult] = useState(); - - const start = useCallback( - (...args: Args) => { - setLoading(true); - setResult(undefined); - setError(undefined); - fn(...args) - .then((r) => isMounted() && setResult(r)) - .catch((e) => isMounted() && setError(e)) - .finally(() => isMounted() && setLoading(false)); - }, - [fn, isMounted] - ); - - return { - error, - loading, - result, - start, - }; -}; diff --git a/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.test.ts b/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.test.ts deleted file mode 100644 index a8013a65441c9..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { renderHook } from '@testing-library/react'; - -import { useIsMounted } from '.'; - -describe('useIsMounted', () => { - it('evaluates to true when mounted', () => { - const { result } = renderHook(() => useIsMounted()); - - expect(result.current()).toEqual(true); - }); - - it('evaluates to false when unmounted', () => { - const { result, unmount } = renderHook(() => useIsMounted()); - - unmount(); - expect(result.current()).toEqual(false); - }); -}); diff --git a/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.ts b/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.ts deleted file mode 100644 index b563840d2f73a..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useCallback, useEffect, useRef } from 'react'; - -type GetIsMounted = () => boolean; - -/** - * - * @returns A {@link GetIsMounted} getter function returning whether the component is currently mounted - */ -export const useIsMounted = (): GetIsMounted => { - const isMounted = useRef(false); - const getIsMounted: GetIsMounted = useCallback(() => isMounted.current, []); - const handleCleanup = useCallback(() => { - isMounted.current = false; - }, []); - - useEffect(() => { - isMounted.current = true; - return handleCleanup; - }, [handleCleanup]); - - return getIsMounted; -}; diff --git a/packages/kbn-securitysolution-hook-utils/src/use_observable/index.test.ts b/packages/kbn-securitysolution-hook-utils/src/use_observable/index.test.ts deleted file mode 100644 index 8d90bffeb3ee2..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/src/use_observable/index.test.ts +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { renderHook, act } from '@testing-library/react'; -import { Subject, throwError } from 'rxjs'; - -import { useObservable } from '.'; - -interface TestArgs { - n: number; - s: string; -} - -type TestReturn = Subject; - -describe('useObservable', () => { - let fn: jest.Mock; - let subject: TestReturn; - let args: TestArgs; - - beforeEach(() => { - args = { n: 1, s: 's' }; - subject = new Subject(); - fn = jest.fn().mockReturnValue(subject); - }); - - it('does not invoke fn if start was not called', () => { - renderHook(() => useObservable(fn)); - expect(fn).not.toHaveBeenCalled(); - }); - - it('invokes the function when start is called', () => { - const { result } = renderHook(() => useObservable(fn)); - - act(() => { - result.current.start(args); - }); - - expect(fn).toHaveBeenCalled(); - }); - - it('invokes the function with start args', () => { - const { result } = renderHook(() => useObservable(fn)); - const expectedArgs = { ...args }; - - act(() => { - result.current.start(args); - }); - - expect(fn).toHaveBeenCalledWith(expectedArgs); - }); - - it('populates result with the next value of the fn', () => { - const { result } = renderHook(() => useObservable(fn)); - - act(() => { - result.current.start(args); - }); - act(() => subject.next('value')); - - expect(result.current.result).toEqual('value'); - expect(result.current.error).toBeUndefined(); - }); - - it('populates error if observable throws an error', () => { - const error = new Error('whoops'); - const errorFn = () => throwError(error); - - const { result } = renderHook(() => useObservable(errorFn)); - - act(() => { - result.current.start(); - }); - - expect(result.current.result).toBeUndefined(); - expect(result.current.error).toEqual(error); - }); - - it('populates the loading state while no value has resolved', () => { - const { result } = renderHook(() => useObservable(fn)); - - act(() => { - result.current.start(args); - }); - - expect(result.current.loading).toBe(true); - - act(() => subject.next('a value')); - - expect(result.current.loading).toBe(false); - }); - - it('updates result with each resolved value', () => { - const { result } = renderHook(() => useObservable(fn)); - - act(() => { - result.current.start(args); - }); - - act(() => subject.next('a value')); - expect(result.current.result).toEqual('a value'); - - act(() => subject.next('a subsequent value')); - expect(result.current.result).toEqual('a subsequent value'); - }); - - it('does not update result with values if start has not been called', () => { - const { result } = renderHook(() => useObservable(fn)); - - act(() => subject.next('a value')); - expect(result.current.result).toBeUndefined(); - - act(() => subject.next('a subsequent value')); - expect(result.current.result).toBeUndefined(); - }); - - it('unsubscribes on unmount', () => { - const { result, unmount } = renderHook(() => useObservable(fn)); - - act(() => { - result.current.start(args); - }); - expect(subject.observers).toHaveLength(1); - - unmount(); - expect(subject.observers).toHaveLength(0); - }); - - it('multiple start calls reset state', () => { - const { result } = renderHook(() => useObservable(fn)); - - act(() => { - result.current.start(args); - }); - - expect(result.current.loading).toBe(true); - - act(() => subject.next('one value')); - - expect(result.current.loading).toBe(false); - expect(result.current.result).toBe('one value'); - - act(() => { - result.current.start(args); - }); - - expect(result.current.loading).toBe(true); - expect(result.current.result).toBe(undefined); - - act(() => subject.next('another value')); - - expect(result.current.loading).toBe(false); - expect(result.current.result).toBe('another value'); - }); -}); diff --git a/packages/kbn-securitysolution-hook-utils/src/use_observable/index.ts b/packages/kbn-securitysolution-hook-utils/src/use_observable/index.ts deleted file mode 100644 index 0b7f9ab93e022..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/src/use_observable/index.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useCallback, useEffect, useRef, useReducer, Reducer } from 'react'; -import { Observable, Subscription } from 'rxjs'; - -import { useIsMounted } from '../use_is_mounted'; -import { Task } from '../types'; - -interface State { - loading: boolean; - error?: unknown; - result?: T; -} - -export type Action = - | { type: 'setResult'; result: T } - | { type: 'setError'; error: unknown } - | { type: 'load' }; - -function reducer(state: State, action: Action) { - switch (action.type) { - case 'setResult': - return { ...state, result: action.result, loading: false }; - case 'setError': - return { ...state, error: action.error, loading: false }; - case 'load': - return { loading: true, result: undefined, error: undefined }; - } -} - -/** - * - * @param fn function returning an observable - * - * @returns An {@link Async} containing the underlying task's state along with a start callback - */ -export const useObservable = ( - fn: (...args: Args) => Observable -): Task => { - const isMounted = useIsMounted(); - const subRef = useRef(); - const [state, dispatch] = useReducer, Action>>(reducer, { - loading: false, - error: undefined, - result: undefined, - }); - - const start = useCallback( - (...args: Args) => { - if (subRef.current) { - subRef.current.unsubscribe(); - } - dispatch({ type: 'load' }); - - subRef.current = fn(...args).subscribe( - (r) => { - if (isMounted()) { - dispatch({ type: 'setResult', result: r }); - } - }, - (e) => { - if (isMounted()) { - dispatch({ type: 'setError', error: e }); - } - } - ); - }, - [fn, isMounted] - ); - - useEffect( - () => () => { - if (subRef.current) { - subRef.current.unsubscribe(); - } - }, - [] - ); - - return { - result: state.result, - error: state.error, - loading: state.loading, - start, - }; -}; diff --git a/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.test.ts b/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.test.ts deleted file mode 100644 index fa77482d24bed..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { withOptionalSignal } from '.'; - -type TestFn = ({ number, signal }: { number: number; signal: AbortSignal }) => boolean; - -describe('withOptionalSignal', () => { - it('does not require a signal on the returned function', () => { - const fn = jest.fn().mockReturnValue('hello') as TestFn; - - const wrappedFn = withOptionalSignal(fn); - - expect(wrappedFn({ number: 1 })).toEqual('hello'); - }); - - it('will pass a given signal to the wrapped function', () => { - const fn = jest.fn().mockReturnValue('hello') as TestFn; - const { signal } = new AbortController(); - - const wrappedFn = withOptionalSignal(fn); - - wrappedFn({ number: 1, signal }); - expect(fn).toHaveBeenCalledWith({ number: 1, signal }); - }); -}); diff --git a/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.ts b/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.ts deleted file mode 100644 index eb7cffeb7e003..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -interface SignalArgs { - signal: AbortSignal; -} - -export type OptionalSignalArgs = Omit & Partial; - -/** - * - * @param fn an async function receiving an AbortSignal argument - * - * @returns An async function where the AbortSignal argument is optional - */ -export const withOptionalSignal = - (fn: (args: Args) => Result) => - (args: OptionalSignalArgs): Result => { - const signal = args.signal != null ? args.signal : new AbortController().signal; - return fn({ ...args, signal } as Args); - }; diff --git a/packages/kbn-securitysolution-hook-utils/tsconfig.json b/packages/kbn-securitysolution-hook-utils/tsconfig.json deleted file mode 100644 index 9b5c5373afe0e..0000000000000 --- a/packages/kbn-securitysolution-hook-utils/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": ["jest", "node"] - }, - "include": [ - "**/*.ts" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/index.ts deleted file mode 100644 index 6baaf0a704036..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './src/actions'; -export * from './src/default_actions_array'; -export * from './src/default_export_file_name'; -export * from './src/default_from_string'; -export * from './src/default_interval_string'; -export * from './src/default_language_string'; -export * from './src/default_max_signals_number'; -export * from './src/default_page'; -export * from './src/default_per_page'; -export * from './src/default_risk_score_mapping_array'; -export * from './src/default_severity_mapping_array'; -export * from './src/default_threat_array'; -export * from './src/default_to_string'; -export * from './src/default_uuid'; -export * from './src/frequency'; -export * from './src/language'; -export * from './src/machine_learning_job_id'; -export * from './src/max_signals'; -export * from './src/normalized_ml_job_id'; -export * from './src/references_default_array'; -export * from './src/risk_score'; -export * from './src/risk_score_mapping'; -export * from './src/rule_schedule'; -export * from './src/saved_object_attributes'; -export * from './src/severity'; -export * from './src/severity_mapping'; -export * from './src/threat'; -export * from './src/threat_mapping'; -export * from './src/threat_subtechnique'; -export * from './src/threat_tactic'; -export * from './src/threat_technique'; -export * from './src/throttle'; -export * from './src/type'; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/jest.config.js b/packages/kbn-securitysolution-io-ts-alerting-types/jest.config.js deleted file mode 100644 index b4c7014f91544..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-io-ts-alerting-types'], -}; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/package.json b/packages/kbn-securitysolution-io-ts-alerting-types/package.json deleted file mode 100644 index ab19f69d20b3f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@kbn/securitysolution-io-ts-alerting-types", - "version": "1.0.0", - "description": "io ts utilities and types to be shared with plugins from the security solution project", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true, - "sideEffects": false -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts deleted file mode 100644 index ad1dde3da7450..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; - -import * as t from 'io-ts'; -import { saved_object_attributes } from '../saved_object_attributes'; -import { RuleActionFrequency } from '../frequency'; - -export type RuleActionGroup = t.TypeOf; -export const RuleActionGroup = t.string; - -export type RuleActionId = t.TypeOf; -export const RuleActionId = t.string; - -export type RuleActionTypeId = t.TypeOf; -export const RuleActionTypeId = t.string; - -export type RuleActionUuid = t.TypeOf; -export const RuleActionUuid = NonEmptyString; - -/** - * Params is an "object", since it is a type of RuleActionParams which is action templates. - * @see x-pack/plugins/alerting/common/rule.ts - */ -export type RuleActionParams = t.TypeOf; -export const RuleActionParams = saved_object_attributes; - -export const RuleActionAlertsFilter = t.partial({ - query: t.union([ - t.undefined, - t.intersection([ - t.strict({ - kql: t.string, - filters: t.array( - t.intersection([ - t.type({ - meta: t.partial({ - alias: t.union([t.string, t.null]), - disabled: t.boolean, - negate: t.boolean, - controlledBy: t.string, - group: t.string, - index: t.string, - isMultiIndex: t.boolean, - type: t.string, - key: t.string, - params: t.any, - value: t.string, - }), - }), - t.partial({ - $state: t.type({ store: t.any }), - query: t.record(t.string, t.any), - }), - ]) - ), - }), - t.partial({ dsl: t.string }), - ]), - ]), - timeframe: t.union([ - t.undefined, - t.strict({ - timezone: t.string, - days: t.array( - t.union([ - t.literal(1), - t.literal(2), - t.literal(3), - t.literal(4), - t.literal(5), - t.literal(6), - t.literal(7), - ]) - ), - hours: t.strict({ - start: t.string, - end: t.string, - }), - }), - ]), -}); - -export type RuleAction = t.TypeOf; -export const RuleAction = t.exact( - t.intersection([ - t.type({ - group: RuleActionGroup, - id: RuleActionId, - action_type_id: RuleActionTypeId, - params: RuleActionParams, - }), - t.partial({ - uuid: RuleActionUuid, - alerts_filter: RuleActionAlertsFilter, - frequency: RuleActionFrequency, - }), - ]) -); - -export type RuleActionArray = t.TypeOf; -export const RuleActionArray = t.array(RuleAction); - -export type RuleActionCamel = t.TypeOf; -export const RuleActionCamel = t.exact( - t.intersection([ - t.type({ - group: RuleActionGroup, - id: RuleActionId, - actionTypeId: RuleActionTypeId, - params: RuleActionParams, - }), - t.partial({ - uuid: RuleActionUuid, - alertsFilter: RuleActionAlertsFilter, - frequency: RuleActionFrequency, - }), - ]) -); - -export type RuleActionArrayCamel = t.TypeOf; -export const RuleActionArrayCamel = t.array(RuleActionCamel); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.mock.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.mock.ts deleted file mode 100644 index bb398e0df8460..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.mock.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export const ENTRY_VALUE = 'some host name'; -export const FIELD = 'host.name'; -export const MATCH = 'match'; -export const MATCH_ANY = 'match_any'; -export const OPERATOR = 'included'; -export const NESTED = 'nested'; -export const NESTED_FIELD = 'parent.field'; -export const LIST_ID = 'some-list-id'; -export const LIST = 'list'; -export const TYPE = 'ip'; -export const EXISTS = 'exists'; -export const WILDCARD = 'wildcard'; -export const USER = 'some user'; -export const DATE_NOW = '2020-04-20T15:25:31.830Z'; - -// Exception List specific -export const ID = 'uuid_here'; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts deleted file mode 100644 index 0c930e5f4a808..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/** - * TODO: Create a kbn-alerting-constants and add this to it. - * @deprecated Use a DEFAULT_MAX_SIGNALS from a kbn-alerting-constants package. - */ -export const DEFAULT_MAX_SIGNALS = 100; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts deleted file mode 100644 index 17c3f9301c6d7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { RuleActionArray } from '../actions'; - -export const DefaultActionsArray = new t.Type< - RuleActionArray, - RuleActionArray | undefined, - unknown ->( - 'DefaultActionsArray', - RuleActionArray.is, - (input, context): Either => - input == null ? t.success([]) : RuleActionArray.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.test.ts deleted file mode 100644 index b07ade238db28..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultExportFileName } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_export_file_name', () => { - test('it should validate a regular string', () => { - const payload = 'some string'; - const decoded = DefaultExportFileName.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate a number', () => { - const payload = 5; - const decoded = DefaultExportFileName.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "DefaultExportFileName"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default of "export.ndjson"', () => { - const payload = null; - const decoded = DefaultExportFileName.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual('export.ndjson'); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.ts deleted file mode 100644 index dedbadfa6f522..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; - -/** - * Types the DefaultExportFileName as: - * - If null or undefined, then a default of "export.ndjson" will be used - */ -export const DefaultExportFileName = new t.Type( - 'DefaultExportFileName', - t.string.is, - (input, context): Either => - input == null ? t.success('export.ndjson') : t.string.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.test.ts deleted file mode 100644 index 2515b3f8b0152..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultFromString } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_from_string', () => { - test('it should validate a from string', () => { - const payload = 'now-20m'; - const decoded = DefaultFromString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate a number', () => { - const payload = 5; - const decoded = DefaultFromString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "DefaultFromString"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default of "now-6m"', () => { - const payload = null; - const decoded = DefaultFromString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual('now-6m'); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts deleted file mode 100644 index ccf70aab8a7b9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { From } from '../from'; - -/** - * Types the DefaultFromString as: - * - If null or undefined, then a default of the string "now-6m" will be used - */ -export const DefaultFromString = new t.Type( - 'DefaultFromString', - t.string.is, - (input, context): Either => { - if (input == null) { - return t.success('now-6m'); - } - return From.validate(input, context); - }, - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.test.ts deleted file mode 100644 index 8944d57ba8999..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultIntervalString } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_interval_string', () => { - test('it should validate a interval string', () => { - const payload = '20m'; - const decoded = DefaultIntervalString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate a number', () => { - const payload = 5; - const decoded = DefaultIntervalString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "DefaultIntervalString"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default of "5m"', () => { - const payload = null; - const decoded = DefaultIntervalString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual('5m'); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.ts deleted file mode 100644 index 3fc5d4f42ccbd..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; - -/** - * Types the DefaultIntervalString as: - * - If null or undefined, then a default of the string "5m" will be used - */ -export const DefaultIntervalString = new t.Type( - 'DefaultIntervalString', - t.string.is, - (input, context): Either => - input == null ? t.success('5m') : t.string.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.test.ts deleted file mode 100644 index 4a8d50c88eaa8..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { Language } from '../language'; -import { DefaultLanguageString } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_language_string', () => { - test('it should validate a string', () => { - const payload: Language = 'lucene'; - const decoded = DefaultLanguageString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate a number', () => { - const payload = 5; - const decoded = DefaultLanguageString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "DefaultLanguageString"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default of "kuery"', () => { - const payload = null; - const decoded = DefaultLanguageString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual('kuery'); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.ts deleted file mode 100644 index 02328d94b0114..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { language } from '../language'; - -/** - * Types the DefaultLanguageString as: - * - If null or undefined, then a default of the string "kuery" will be used - */ -export const DefaultLanguageString = new t.Type( - 'DefaultLanguageString', - t.string.is, - (input, context): Either => - input == null ? t.success('kuery') : language.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.test.ts deleted file mode 100644 index 66eb77400ac1d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultMaxSignalsNumber } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { DEFAULT_MAX_SIGNALS } from '../constants'; - -describe('default_from_string', () => { - test('it should validate a max signal number', () => { - const payload = 5; - const decoded = DefaultMaxSignalsNumber.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate a string', () => { - const payload = '5'; - const decoded = DefaultMaxSignalsNumber.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "DefaultMaxSignals"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not validate a zero', () => { - const payload = 0; - const decoded = DefaultMaxSignalsNumber.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "DefaultMaxSignals"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not validate a negative number', () => { - const payload = -1; - const decoded = DefaultMaxSignalsNumber.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "DefaultMaxSignals"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default of DEFAULT_MAX_SIGNALS', () => { - const payload = null; - const decoded = DefaultMaxSignalsNumber.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(DEFAULT_MAX_SIGNALS); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.ts deleted file mode 100644 index 8acbc2f223a14..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { max_signals } from '../max_signals'; -import { DEFAULT_MAX_SIGNALS } from '../constants'; - -/** - * Types the default max signal: - * - Natural Number (positive integer and not a float), - * - greater than 1 - * - If undefined then it will use DEFAULT_MAX_SIGNALS (100) as the default - */ -export const DefaultMaxSignalsNumber = new t.Type( - 'DefaultMaxSignals', - t.number.is, - (input, context): Either => { - return input == null ? t.success(DEFAULT_MAX_SIGNALS) : max_signals.validate(input, context); - }, - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.test.ts deleted file mode 100644 index 5af986fefe8dd..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultPage } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_page', () => { - test('it should validate a regular number greater than zero', () => { - const payload = 5; - const decoded = DefaultPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate a string of a number', () => { - const payload = '5'; - const decoded = DefaultPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(5); - }); - - test('it should not validate a junk string', () => { - const payload = 'invalid-string'; - const decoded = DefaultPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "NaN" supplied to "DefaultPerPage"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not validate an empty string', () => { - const payload = ''; - const decoded = DefaultPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "NaN" supplied to "DefaultPerPage"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not validate a zero', () => { - const payload = 0; - const decoded = DefaultPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "DefaultPerPage"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not validate a negative number', () => { - const payload = -1; - const decoded = DefaultPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "DefaultPerPage"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default of 20', () => { - const payload = null; - const decoded = DefaultPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(1); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.ts deleted file mode 100644 index 8486c516aebf7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; - -/** - * Types the DefaultPerPage as: - * - If a string this will convert the string to a number - * - If null or undefined, then a default of 1 will be used - * - If the number is 0 or less this will not validate as it has to be a positive number greater than zero - */ -export const DefaultPage = new t.Type( - 'DefaultPerPage', - t.number.is, - (input, context): Either => { - if (input == null) { - return t.success(1); - } else if (typeof input === 'string') { - return PositiveIntegerGreaterThanZero.validate(parseInt(input, 10), context); - } else { - return PositiveIntegerGreaterThanZero.validate(input, context); - } - }, - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.test.ts deleted file mode 100644 index 78fa2a9be8c82..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultPerPage } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_per_page', () => { - test('it should validate a regular number greater than zero', () => { - const payload = 5; - const decoded = DefaultPerPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate a string of a number', () => { - const payload = '5'; - const decoded = DefaultPerPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(5); - }); - - test('it should not validate a junk string', () => { - const payload = 'invalid-string'; - const decoded = DefaultPerPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "NaN" supplied to "DefaultPerPage"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not validate an empty string', () => { - const payload = ''; - const decoded = DefaultPerPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "NaN" supplied to "DefaultPerPage"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not validate a zero', () => { - const payload = 0; - const decoded = DefaultPerPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "DefaultPerPage"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not validate a negative number', () => { - const payload = -1; - const decoded = DefaultPerPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "DefaultPerPage"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default of 20', () => { - const payload = null; - const decoded = DefaultPerPage.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(20); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.ts deleted file mode 100644 index 4f272fc0517eb..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; - -/** - * Types the DefaultPerPage as: - * - If a string this will convert the string to a number - * - If null or undefined, then a default of 20 will be used - * - If the number is 0 or less this will not validate as it has to be a positive number greater than zero - */ -export const DefaultPerPage = new t.Type( - 'DefaultPerPage', - t.number.is, - (input, context): Either => { - if (input == null) { - return t.success(20); - } else if (typeof input === 'string') { - return PositiveIntegerGreaterThanZero.validate(parseInt(input, 10), context); - } else { - return PositiveIntegerGreaterThanZero.validate(input, context); - } - }, - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts deleted file mode 100644 index 9eb6938bcfcbd..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { RiskScoreMapping } from '../risk_score_mapping'; - -/** - * Types the DefaultStringArray as: - * - If null or undefined, then a default RiskScoreMapping array will be set - */ -export const DefaultRiskScoreMappingArray = new t.Type< - RiskScoreMapping, - RiskScoreMapping | undefined, - unknown ->( - 'DefaultRiskScoreMappingArray', - RiskScoreMapping.is, - (input, context): Either => - input == null ? t.success([]) : RiskScoreMapping.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts deleted file mode 100644 index ac72e3330f2a1..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { SeverityMapping } from '../severity_mapping'; - -/** - * Types the DefaultStringArray as: - * - If null or undefined, then a default SeverityMapping array will be set - */ -export const DefaultSeverityMappingArray = new t.Type< - SeverityMapping, - SeverityMapping | undefined, - unknown ->( - 'DefaultSeverityMappingArray', - SeverityMapping.is, - (input, context): Either => - input == null ? t.success([]) : SeverityMapping.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.test.ts deleted file mode 100644 index ebd1ca9384b13..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { Threats } from '../threat'; -import { DefaultThreatArray } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_threat_null', () => { - test('it should validate an empty array', () => { - const payload: Threats = []; - const decoded = DefaultThreatArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of threats', () => { - const payload: Threats = [ - { - framework: 'MITRE ATTACK', - technique: [{ reference: 'https://test.com', name: 'Audio Capture', id: 'T1123' }], - tactic: { reference: 'https://test.com', name: 'Collection', id: 'TA000999' }, - }, - ]; - const decoded = DefaultThreatArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate an array with a number', () => { - const payload = [ - { - framework: 'MITRE ATTACK', - technique: [{ reference: 'https://test.com', name: 'Audio Capture', id: 'T1123' }], - tactic: { reference: 'https://test.com', name: 'Collection', id: 'TA000999' }, - }, - 5, - ]; - const decoded = DefaultThreatArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "DefaultThreatArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default empty array if not provided a value', () => { - const payload = null; - const decoded = DefaultThreatArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([]); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.ts deleted file mode 100644 index bb38b6382230c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { threats, Threats } from '../threat'; - -/** - * Types the DefaultThreatArray as: - * - If null or undefined, then an empty array will be set - */ -export const DefaultThreatArray = new t.Type( - 'DefaultThreatArray', - threats.is, - (input, context): Either => - input == null ? t.success([]) : threats.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.test.ts deleted file mode 100644 index e8bcdcc664cfe..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultToString } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_to_string', () => { - test('it should validate a to string', () => { - const payload = 'now-5m'; - const decoded = DefaultToString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate a number', () => { - const payload = 5; - const decoded = DefaultToString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "DefaultToString"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default of "now"', () => { - const payload = null; - const decoded = DefaultToString.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual('now'); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.ts deleted file mode 100644 index 4074cc3bbbe9e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; - -/** - * Types the DefaultToString as: - * - If null or undefined, then a default of the string "now" will be used - */ -export const DefaultToString = new t.Type( - 'DefaultToString', - t.string.is, - (input, context): Either => - input == null ? t.success('now') : t.string.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.ts deleted file mode 100644 index 4144b4e6824ce..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { v4 as uuidv4 } from 'uuid'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; - -/** - * Types the DefaultUuid as: - * - If null or undefined, then a default string uuidv4() will be - * created otherwise it will be checked just against an empty string - */ -export const DefaultUuid = new t.Type( - 'DefaultUuid', - t.string.is, - (input, context): Either => - input == null ? t.success(uuidv4()) : NonEmptyString.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/frequency/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/frequency/index.ts deleted file mode 100644 index 0247bfb155f32..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/frequency/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { RuleActionThrottle } from '../throttle'; - -/** - * Action summary indicates whether we will send a summary notification about all the generate alerts or notification per individual alert - */ -export type RuleActionSummary = t.TypeOf; -export const RuleActionSummary = t.boolean; - -/** - * The condition for throttling the notification: `onActionGroupChange`, `onActiveAlert`, or `onThrottleInterval` - */ -export type RuleActionNotifyWhen = t.TypeOf; -export const RuleActionNotifyWhen = t.union([ - t.literal('onActionGroupChange'), - t.literal('onActiveAlert'), - t.literal('onThrottleInterval'), -]); - -/** - * The action frequency defines when the action runs (for example, only on rule execution or at specific time intervals). - */ -export type RuleActionFrequency = t.TypeOf; -export const RuleActionFrequency = t.type({ - summary: RuleActionSummary, - notifyWhen: RuleActionNotifyWhen, - throttle: t.union([RuleActionThrottle, t.null]), -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts deleted file mode 100644 index 390649416273d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { Either } from 'fp-ts/lib/Either'; -import * as t from 'io-ts'; -import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; - -const stringValidator = (input: unknown): input is string => typeof input === 'string'; - -export type From = t.TypeOf; -export const From = new t.Type( - 'From', - t.string.is, - (input, context): Either => { - if (stringValidator(input) && parseScheduleDates(input) == null) { - return t.failure(input, context, 'Failed to parse "from" on rule param'); - } - return t.string.validate(input, context); - }, - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts deleted file mode 100644 index 95017209b2c6d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const language = t.keyof({ eql: null, kuery: null, lucene: null, esql: null }); -export type Language = t.TypeOf; - -export const languageOrUndefined = t.union([language, t.undefined]); -export type LanguageOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts deleted file mode 100644 index 00dc70eb55751..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -import { machine_learning_job_id_normalized } from '../normalized_ml_job_id'; - -export const machine_learning_job_id = t.union([t.string, machine_learning_job_id_normalized]); -export type MachineLearningJobId = t.TypeOf; - -export const machineLearningJobIdOrUndefined = t.union([machine_learning_job_id, t.undefined]); -export type MachineLearningJobIdOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts deleted file mode 100644 index aa8bdf6f539af..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; -import { PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; - -export const max_signals = PositiveIntegerGreaterThanZero; -export type MaxSignals = t.TypeOf; - -export const maxSignalsOrUndefined = t.union([max_signals, t.undefined]); -export type MaxSignalsOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts deleted file mode 100644 index 2d89147c4fa11..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -import { NonEmptyArray } from '@kbn/securitysolution-io-ts-types'; - -export const machine_learning_job_id_normalized = NonEmptyArray(t.string); -export type MachineLearningJobIdNormalized = t.TypeOf; - -export const machineLearningJobIdNormalizedOrUndefined = t.union([ - machine_learning_job_id_normalized, - t.undefined, -]); -export type MachineLearningJobIdNormalizedOrUndefined = t.TypeOf< - typeof machineLearningJobIdNormalizedOrUndefined ->; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.test.ts deleted file mode 100644 index 7b6146a320d6b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { ReferencesDefaultArray } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_string_array', () => { - test('it should validate an empty array', () => { - const payload: string[] = []; - const decoded = ReferencesDefaultArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of strings', () => { - const payload = ['value 1', 'value 2']; - const decoded = ReferencesDefaultArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate an array with a number', () => { - const payload = ['value 1', 5]; - const decoded = ReferencesDefaultArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "referencesWithDefaultArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default array entry', () => { - const payload = null; - const decoded = ReferencesDefaultArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([]); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.ts deleted file mode 100644 index fcf22ad918c9b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; - -/** - * Types the ReferencesDefaultArray as: - * - If null or undefined, then a default array will be set - */ -export const ReferencesDefaultArray = new t.Type( - 'referencesWithDefaultArray', - t.array(t.string).is, - (input, context): Either => - input == null ? t.success([]) : t.array(t.string).validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.test.ts deleted file mode 100644 index 85d83d0ec77d7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { RiskScore } from '.'; - -describe('risk_score', () => { - test('it should validate a positive number', () => { - const payload = 1; - const decoded = RiskScore.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate a zero', () => { - const payload = 0; - const decoded = RiskScore.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT validate a negative number', () => { - const payload = -1; - const decoded = RiskScore.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "-1" supplied to "RiskScore"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT validate a string', () => { - const payload = 'some string'; - const decoded = RiskScore.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some string" supplied to "RiskScore"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT validate a risk score greater than 100', () => { - const payload = 101; - const decoded = RiskScore.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "101" supplied to "RiskScore"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts deleted file mode 100644 index ecc48e9a699de..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; - -/** - * Types the risk score as: - * - Natural Number (positive integer and not a float), - * - Between the values [0 and 100] inclusive. - */ -export type RiskScore = t.TypeOf; -export const RiskScore = new t.Type( - 'RiskScore', - t.number.is, - (input, context): Either => { - return typeof input === 'number' && Number.isSafeInteger(input) && input >= 0 && input <= 100 - ? t.success(input) - : t.failure(input, context); - }, - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts deleted file mode 100644 index 59f7c7ab69fbe..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { operator } from '@kbn/securitysolution-io-ts-types'; -import { RiskScore } from '../risk_score'; - -export type RiskScoreMappingItem = t.TypeOf; -export const RiskScoreMappingItem = t.exact( - t.type({ - field: t.string, - value: t.string, - operator, - risk_score: t.union([RiskScore, t.undefined]), - }) -); - -export type RiskScoreMapping = t.TypeOf; -export const RiskScoreMapping = t.array(RiskScoreMappingItem); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts deleted file mode 100644 index 4d0113f330ae9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { From } from '../from'; - -export type RuleInterval = t.TypeOf; -export const RuleInterval = t.string; // we need a more specific schema - -export type RuleIntervalFrom = t.TypeOf; -export const RuleIntervalFrom = From; - -/** - * TODO: Create a regular expression type or custom date math part type here - */ -export type RuleIntervalTo = t.TypeOf; -export const RuleIntervalTo = t.string; // we need a more specific schema diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/saved_object_attributes/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/saved_object_attributes/index.ts deleted file mode 100644 index 2a7af4e665183..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/saved_object_attributes/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -/** - * TODO: This type are originally from "src/core/types/saved_objects.ts", once that is package friendly remove - * this copied type. - * - * Don't use this type, it's simply a helper type for {@link SavedObjectAttribute} - * - * @public - */ -export type SavedObjectAttributeSingle = - | string - | number - | boolean - | null - | undefined - | SavedObjectAttributes; - -/** - * TODO: This type are originally from "src/core/types/saved_objects.ts", once that is package friendly remove - * this copied type. - * - * Type definition for a Saved Object attribute value - * - * @public - */ -export type SavedObjectAttribute = SavedObjectAttributeSingle | SavedObjectAttributeSingle[]; - -/** - * TODO: This type are originally from "src/core/types/saved_objects.ts", once that is package friendly remove - * this copied type. - * - * The data for a Saved Object is stored as an object in the `attributes` - * property. - * - * @public - */ -export interface SavedObjectAttributes { - [key: string]: SavedObjectAttribute; -} - -export const saved_object_attribute_single: t.Type = t.recursion( - 'saved_object_attribute_single', - () => t.union([t.string, t.number, t.boolean, t.null, t.undefined, saved_object_attributes]) -); -export const saved_object_attribute: t.Type = t.recursion( - 'saved_object_attribute', - () => t.union([saved_object_attribute_single, t.array(saved_object_attribute_single)]) -); -export const saved_object_attributes: t.Type = t.recursion( - 'saved_object_attributes', - () => t.record(t.string, saved_object_attribute) -); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts deleted file mode 100644 index fef1082129df8..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export type Severity = t.TypeOf; -export const Severity = t.keyof({ low: null, medium: null, high: null, critical: null }); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts deleted file mode 100644 index afd7889658a35..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { operator } from '@kbn/securitysolution-io-ts-types'; -import { Severity } from '../severity'; - -export type SeverityMappingItem = t.TypeOf; -export const SeverityMappingItem = t.exact( - t.type({ - field: t.string, - operator, - value: t.string, - severity: Severity, - }) -); - -export type SeverityMapping = t.TypeOf; -export const SeverityMapping = t.array(SeverityMappingItem); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/threat/index.ts deleted file mode 100644 index e60f9ccafcc13..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; -import { threat_tactic } from '../threat_tactic'; -import { threat_techniques } from '../threat_technique'; - -export const threat_framework = t.string; - -export const threat = t.intersection([ - t.exact( - t.type({ - framework: threat_framework, - tactic: threat_tactic, - }) - ), - t.exact( - t.partial({ - technique: threat_techniques, - }) - ), -]); - -export type Threat = t.TypeOf; - -export const threats = t.array(threat); -export type Threats = t.TypeOf; - -export const threatsOrUndefined = t.union([threats, t.undefined]); -export type ThreatsOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.test.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.test.ts deleted file mode 100644 index 3d3e1ab9a22bf..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.test.ts +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { - concurrent_searches, - items_per_search, - ThreatMapping, - threatMappingEntries, - ThreatMappingEntries, - threat_mapping, -} from '.'; -import { foldLeftRight, getPaths, exactCheck } from '@kbn/securitysolution-io-ts-utils'; - -describe('threat_mapping', () => { - describe('threatMappingEntries', () => { - test('it should validate an entry', () => { - const payload: ThreatMappingEntries = [ - { - field: 'field.one', - type: 'mapping', - value: 'field.one', - }, - ]; - const decoded = threatMappingEntries.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation with an extra entry item', () => { - const payload: Array = [ - { - field: 'field.one', - type: 'mapping', - value: 'field.one', - extra: 'blah', - }, - ]; - const decoded = threatMappingEntries.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extra"']); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation with a non string', () => { - const payload = [ - { - field: 5, - type: 'mapping', - value: 'field.one', - }, - ] as unknown as ThreatMappingEntries[]; - const decoded = threatMappingEntries.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation with a wrong type', () => { - const payload = [ - { - field: 'field.one', - type: 'invalid', - value: 'field.one', - }, - ] as unknown as ThreatMappingEntries[]; - const decoded = threatMappingEntries.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "invalid" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('threat_mapping', () => { - test('it should validate a threat mapping', () => { - const payload: ThreatMapping = [ - { - entries: [ - { - field: 'field.one', - type: 'mapping', - value: 'field.one', - }, - ], - }, - ]; - const decoded = threat_mapping.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - }); - - test('it should fail validate with an extra key', () => { - const payload: Array = [ - { - entries: [ - { - field: 'field.one', - type: 'mapping', - value: 'field.one', - }, - ], - extra: 'invalid', - }, - ]; - - const decoded = threat_mapping.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extra"']); - expect(message.schema).toEqual({}); - }); - - test('it should fail validate with an extra inner entry', () => { - const payload: Array }> = [ - { - entries: [ - { - field: 'field.one', - type: 'mapping', - value: 'field.one', - extra: 'blah', - }, - ], - }, - ]; - - const decoded = threat_mapping.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extra"']); - expect(message.schema).toEqual({}); - }); - - test('it should fail validate with an extra inner entry with the wrong data type', () => { - const payload = [ - { - entries: [ - { - field: 5, - type: 'mapping', - value: 'field.one', - }, - ], - }, - ] as unknown as ThreatMapping; - - const decoded = threat_mapping.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "entries,field"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validate with empty array', () => { - const payload: string[] = []; - - const decoded = threat_mapping.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "[]" supplied to "NonEmptyArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when concurrent_searches is < 0', () => { - const payload = -1; - const decoded = concurrent_searches.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "PositiveIntegerGreaterThanZero"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when concurrent_searches is 0', () => { - const payload = 0; - const decoded = concurrent_searches.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "PositiveIntegerGreaterThanZero"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when items_per_search is 0', () => { - const payload = 0; - const decoded = items_per_search.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "PositiveIntegerGreaterThanZero"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when items_per_search is < 0', () => { - const payload = -1; - const decoded = items_per_search.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "PositiveIntegerGreaterThanZero"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts deleted file mode 100644 index 0cc8c950f7549..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; -import { - NonEmptyArray, - NonEmptyString, - PositiveIntegerGreaterThanZero, -} from '@kbn/securitysolution-io-ts-types'; -import { language } from '../language'; - -export const threat_query = t.string; -export type ThreatQuery = t.TypeOf; -export const threatQueryOrUndefined = t.union([threat_query, t.undefined]); -export type ThreatQueryOrUndefined = t.TypeOf; - -export const threat_indicator_path = t.string; -export type ThreatIndicatorPath = t.TypeOf; -export const threatIndicatorPathOrUndefined = t.union([threat_indicator_path, t.undefined]); -export type ThreatIndicatorPathOrUndefined = t.TypeOf; - -export const threat_filters = t.array(t.unknown); // Filters are not easily type-able yet -export type ThreatFilters = t.TypeOf; -export const threatFiltersOrUndefined = t.union([threat_filters, t.undefined]); -export type ThreatFiltersOrUndefined = t.TypeOf; - -export const threatMapEntry = t.exact( - t.type({ - field: NonEmptyString, - type: t.keyof({ mapping: null }), - value: NonEmptyString, - }) -); - -export type ThreatMapEntry = t.TypeOf; - -export const threatMappingEntries = t.array(threatMapEntry); -export type ThreatMappingEntries = t.TypeOf; - -export const threatMap = t.exact( - t.type({ - entries: threatMappingEntries, - }) -); -export type ThreatMap = t.TypeOf; - -export const threat_mapping = NonEmptyArray(threatMap, 'NonEmptyArray'); -export type ThreatMapping = t.TypeOf; - -export const threatMappingOrUndefined = t.union([threat_mapping, t.undefined]); -export type ThreatMappingOrUndefined = t.TypeOf; - -export const threat_index = t.array(t.string); -export type ThreatIndex = t.TypeOf; -export const threatIndexOrUndefined = t.union([threat_index, t.undefined]); -export type ThreatIndexOrUndefined = t.TypeOf; - -export const threat_language = t.union([language, t.undefined]); -export type ThreatLanguage = t.TypeOf; -export const threatLanguageOrUndefined = t.union([threat_language, t.undefined]); -export type ThreatLanguageOrUndefined = t.TypeOf; - -export const concurrent_searches = PositiveIntegerGreaterThanZero; -export type ConcurrentSearches = t.TypeOf; -export const concurrentSearchesOrUndefined = t.union([concurrent_searches, t.undefined]); -export type ConcurrentSearchesOrUndefined = t.TypeOf; - -export const items_per_search = PositiveIntegerGreaterThanZero; -export type ItemsPerSearch = t.TypeOf; -export const itemsPerSearchOrUndefined = t.union([items_per_search, t.undefined]); -export type ItemsPerSearchOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_subtechnique/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_subtechnique/index.ts deleted file mode 100644 index 963bf76bf5f87..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_subtechnique/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const threat_subtechnique_id = t.string; -export const threat_subtechnique_name = t.string; -export const threat_subtechnique_reference = t.string; - -export const threat_subtechnique = t.type({ - id: threat_subtechnique_id, - name: threat_subtechnique_name, - reference: threat_subtechnique_reference, -}); - -export const threat_subtechniques = t.array(threat_subtechnique); - -export type ThreatSubtechnique = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_tactic/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_tactic/index.ts deleted file mode 100644 index a142788876e7d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_tactic/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const threat_tactic_id = t.string; -export const threat_tactic_name = t.string; -export const threat_tactic_reference = t.string; - -export const threat_tactic = t.type({ - id: threat_tactic_id, - name: threat_tactic_name, - reference: threat_tactic_reference, -}); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_technique/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_technique/index.ts deleted file mode 100644 index 2953ea86b3b3d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_technique/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; -import { threat_subtechniques } from '../threat_subtechnique'; - -export const threat_technique_id = t.string; -export const threat_technique_name = t.string; -export const threat_technique_reference = t.string; - -export const threat_technique = t.intersection([ - t.exact( - t.type({ - id: threat_technique_id, - name: threat_technique_name, - reference: threat_technique_reference, - }) - ), - t.exact( - t.partial({ - subtechnique: threat_subtechniques, - }) - ), -]); -export const threat_techniques = t.array(threat_technique); - -export type ThreatTechnique = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts deleted file mode 100644 index f1d6bdca8fed9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { TimeDuration } from '@kbn/securitysolution-io-ts-types'; - -export type RuleActionThrottle = t.TypeOf; -export const RuleActionThrottle = t.union([ - t.literal('no_actions'), - t.literal('rule'), - TimeDuration({ allowedUnits: ['s', 'm', 'h', 'd'] }), -]); diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/type/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/type/index.ts deleted file mode 100644 index 68c7a2f30a2bb..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/type/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const type = t.keyof({ - eql: null, - machine_learning: null, - query: null, - saved_query: null, - threshold: null, - threat_match: null, - new_terms: null, - esql: null, -}); -export type Type = t.TypeOf; - -export const typeOrUndefined = t.union([type, t.undefined]); -export type TypeOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/tsconfig.json b/packages/kbn-securitysolution-io-ts-alerting-types/tsconfig.json deleted file mode 100644 index f9fb0b0fcebb2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-alerting-types/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/securitysolution-io-ts-types", - "@kbn/securitysolution-io-ts-utils" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-io-ts-list-types/index.ts b/packages/kbn-securitysolution-io-ts-list-types/index.ts deleted file mode 100644 index 6d6b4e241b6d1..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './src/common'; -export * from './src/request'; -export * from './src/response'; -export * from './src/typescript_types'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/jest.config.js b/packages/kbn-securitysolution-io-ts-list-types/jest.config.js deleted file mode 100644 index adcf48629dd7d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-io-ts-list-types'], -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/package.json b/packages/kbn-securitysolution-io-ts-list-types/package.json deleted file mode 100644 index 50c88fb22054f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@kbn/securitysolution-io-ts-list-types", - "version": "1.0.0", - "description": "io ts utilities and types to be shared with plugins from the security solution project", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true, - "sideEffects": false -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.mock.ts deleted file mode 100644 index d824f23fe74b8..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.mock.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { Comment, CommentsArray } from '.'; -import { DATE_NOW, ID, USER } from '../../constants/index.mock'; - -export const getCommentsMock = (): Comment => ({ - comment: 'some old comment', - created_at: DATE_NOW, - created_by: USER, - id: ID, -}); - -export const getCommentsArrayMock = (): CommentsArray => [getCommentsMock(), getCommentsMock()]; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.test.ts deleted file mode 100644 index deca11f809cbe..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.test.ts +++ /dev/null @@ -1,238 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getCommentsArrayMock, getCommentsMock } from './index.mock'; -import { - Comment, - comment, - CommentsArray, - commentsArray, - CommentsArrayOrUndefined, - commentsArrayOrUndefined, -} from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { DATE_NOW } from '../../constants/index.mock'; - -describe('Comment', () => { - describe('comment', () => { - test('it fails validation when "id" is undefined', () => { - const payload = { ...getCommentsMock(), id: undefined }; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it passes validation with a typical comment', () => { - const payload = getCommentsMock(); - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it passes validation with "updated_at" and "updated_by" fields included', () => { - const payload = getCommentsMock(); - payload.updated_at = DATE_NOW; - payload.updated_by = 'someone'; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it fails validation when undefined', () => { - const payload = undefined; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when "comment" is an empty string', () => { - const payload: Omit & { comment: string } = { - ...getCommentsMock(), - comment: '', - }; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "comment"']); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when "comment" is not a string', () => { - const payload: Omit & { comment: string[] } = { - ...getCommentsMock(), - comment: ['some value'], - }; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "["some value"]" supplied to "comment"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when "created_at" is not a string', () => { - const payload: Omit & { created_at: number } = { - ...getCommentsMock(), - created_at: 1, - }; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "created_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when "created_by" is not a string', () => { - const payload: Omit & { created_by: number } = { - ...getCommentsMock(), - created_by: 1, - }; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "created_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when "updated_at" is not a string', () => { - const payload: Omit & { updated_at: number } = { - ...getCommentsMock(), - updated_at: 1, - }; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "updated_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when "updated_by" is not a string', () => { - const payload: Omit & { updated_by: number } = { - ...getCommentsMock(), - updated_by: 1, - }; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "updated_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: Comment & { - extraKey?: string; - } = getCommentsMock(); - payload.extraKey = 'some value'; - const decoded = comment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getCommentsMock()); - }); - }); - - describe('commentsArray', () => { - test('it passes validation an array of Comment', () => { - const payload = getCommentsArrayMock(); - const decoded = commentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it passes validation when a Comment includes "updated_at" and "updated_by"', () => { - const commentsPayload = getCommentsMock(); - commentsPayload.updated_at = DATE_NOW; - commentsPayload.updated_by = 'someone'; - const payload = [{ ...commentsPayload }, ...getCommentsArrayMock()]; - const decoded = commentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it fails validation when undefined', () => { - const payload = undefined; - const decoded = commentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when array includes non Comment types', () => { - const payload = [1] as unknown as CommentsArray; - const decoded = commentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('commentsArrayOrUndefined', () => { - test('it passes validation an array of Comment', () => { - const payload = getCommentsArrayMock(); - const decoded = commentsArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it passes validation when undefined', () => { - const payload = undefined; - const decoded = commentsArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it fails validation when array includes non Comment types', () => { - const payload = [1] as unknown as CommentsArrayOrUndefined; - const decoded = commentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.ts deleted file mode 100644 index 3aac99e6c48e2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -import { created_at } from '../created_at'; -import { created_by } from '../created_by'; -import { id } from '../id'; -import { updated_at } from '../updated_at'; -import { updated_by } from '../updated_by'; - -export const comment = t.intersection([ - t.exact( - t.type({ - comment: NonEmptyString, - created_at, - created_by, - id, - }) - ), - t.exact( - t.partial({ - updated_at, - updated_by, - }) - ), -]); - -export const commentsArray = t.array(comment); -export type CommentsArray = t.TypeOf; -export type Comment = t.TypeOf; -export const commentsArrayOrUndefined = t.union([commentsArray, t.undefined]); -export type CommentsArrayOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.mock.ts deleted file mode 100644 index bad427de97471..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.mock.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { CreateComment, CreateCommentsArray } from '.'; - -export const getCreateCommentsMock = (): CreateComment => ({ - comment: 'some comments', -}); - -export const getCreateCommentsArrayMock = (): CreateCommentsArray => [getCreateCommentsMock()]; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.test.ts deleted file mode 100644 index c537e9e28091c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.test.ts +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getCreateCommentsArrayMock, getCreateCommentsMock } from './index.mock'; -import { - CreateComment, - createComment, - CreateCommentsArray, - createCommentsArray, - CreateCommentsArrayOrUndefined, - createCommentsArrayOrUndefined, -} from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('CreateComment', () => { - describe('createComment', () => { - test('it passes validation with a default comment', () => { - const payload = getCreateCommentsMock(); - const decoded = createComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it fails validation when undefined', () => { - const payload = undefined; - const decoded = createComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "{| comment: NonEmptyString |}"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when "comment" is not a string', () => { - const payload: Omit & { comment: string[] } = { - ...getCreateCommentsMock(), - comment: ['some value'], - }; - const decoded = createComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "["some value"]" supplied to "comment"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: CreateComment & { - extraKey?: string; - } = getCreateCommentsMock(); - payload.extraKey = 'some value'; - const decoded = createComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getCreateCommentsMock()); - }); - }); - - describe('createCommentsArray', () => { - test('it passes validation an array of comments', () => { - const payload = getCreateCommentsArrayMock(); - const decoded = createCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it fails validation when undefined', () => { - const payload = undefined; - const decoded = createCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "Array<{| comment: NonEmptyString |}>"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when array includes non comments types', () => { - const payload = [1] as unknown as CreateCommentsArray; - const decoded = createCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<{| comment: NonEmptyString |}>"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('createCommentsArrayOrUndefined', () => { - test('it passes validation an array of comments', () => { - const payload = getCreateCommentsArrayMock(); - const decoded = createCommentsArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it passes validation when undefined', () => { - const payload = undefined; - const decoded = createCommentsArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it fails validation when array includes non comments types', () => { - const payload = [1] as unknown as CreateCommentsArrayOrUndefined; - const decoded = createCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<{| comment: NonEmptyString |}>"', - ]); - expect(message.schema).toEqual({}); - }); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.ts deleted file mode 100644 index f4082df289ac2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; - -export const createComment = t.exact( - t.type({ - comment: NonEmptyString, - }) -); - -export type CreateComment = t.TypeOf; -export const createCommentsArray = t.array(createComment); -export type CreateCommentsArray = t.TypeOf; -export type CreateComments = t.TypeOf; -export const createCommentsArrayOrUndefined = t.union([createCommentsArray, t.undefined]); -export type CreateCommentsArrayOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/created_at/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/created_at/index.ts deleted file mode 100644 index 697a5034cbf05..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/created_at/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const created_at = t.string; // TODO: Make this into an ISO Date string check diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/created_by/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/created_by/index.ts deleted file mode 100644 index e6f3e2f90edb4..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/created_by/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const created_by = t.string; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/cursor/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/cursor/index.ts deleted file mode 100644 index 4844ffe7e3640..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/cursor/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const cursor = t.string; -export type Cursor = t.TypeOf; -export const cursorOrUndefined = t.union([cursor, t.undefined]); -export type CursorOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.test.ts deleted file mode 100644 index d0c7e3cc0447a..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { CommentsArray } from '../comment'; -import { DefaultCommentsArray } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getCommentsArrayMock } from '../comment/index.mock'; - -describe('default_comments_array', () => { - test('it should pass validation when supplied an empty array', () => { - const payload: CommentsArray = []; - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should pass validation when supplied an array of comments', () => { - const payload: CommentsArray = getCommentsArrayMock(); - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when supplied an array of numbers', () => { - const payload = [1]; - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an array of strings', () => { - const payload = ['some string']; - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some string" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default array entry', () => { - const payload = null; - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([]); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.ts deleted file mode 100644 index 6a89b00633513..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { comment, CommentsArray } from '../comment'; - -/** - * Types the DefaultCommentsArray as: - * - If null or undefined, then a default array of type entry will be set - */ -export const DefaultCommentsArray = new t.Type( - 'DefaultCommentsArray', - t.array(comment).is, - (input): Either => - input == null ? t.success([]) : t.array(comment).decode(input), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.test.ts deleted file mode 100644 index ce909c0314b3b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { CommentsArray } from '../comment'; -import { DefaultCommentsArray } from '../default_comments_array'; -import { getCommentsArrayMock } from '../comment/index.mock'; - -describe('default_comments_array', () => { - test('it should pass validation when supplied an empty array', () => { - const payload: CommentsArray = []; - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should pass validation when supplied an array of comments', () => { - const payload: CommentsArray = getCommentsArrayMock(); - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when supplied an array of numbers', () => { - const payload = [1]; - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an array of strings', () => { - const payload = ['some string']; - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some string" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default array entry', () => { - const payload = null; - const decoded = DefaultCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([]); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.ts deleted file mode 100644 index 0ed345891719b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { createComment, CreateCommentsArray } from '../create_comment'; - -/** - * Types the DefaultCreateComments as: - * - If null or undefined, then a default array of type entry will be set - */ -export const DefaultCreateCommentsArray = new t.Type< - CreateCommentsArray, - CreateCommentsArray, - unknown ->( - 'DefaultCreateComments', - t.array(createComment).is, - (input): Either => - input == null ? t.success([]) : t.array(createComment).decode(input), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.test.ts deleted file mode 100644 index 9b6f8df6850cb..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { ImportCommentsArray } from '../import_comment'; -import { DefaultImportCommentsArray } from '.'; -import { getCommentsArrayMock } from '../comment/index.mock'; -import { getCreateCommentsArrayMock } from '../create_comment/index.mock'; - -describe('default_import_comments_array', () => { - test('it should pass validation when supplied an empty array', () => { - const payload: ImportCommentsArray = []; - const decoded = DefaultImportCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should pass validation when supplied an array of comments', () => { - const payload: ImportCommentsArray = getCommentsArrayMock(); - const decoded = DefaultImportCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should pass validation when supplied an array of new comments', () => { - const payload: ImportCommentsArray = getCreateCommentsArrayMock(); - const decoded = DefaultImportCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should pass validation when supplied an array of new and existing comments', () => { - const payload: ImportCommentsArray = [ - ...getCommentsArrayMock(), - ...getCreateCommentsArrayMock(), - ]; - const decoded = DefaultImportCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when supplied an array of numbers', () => { - const payload = [1]; - const decoded = DefaultImportCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "DefaultImportComments"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an array of strings', () => { - const payload = ['some string']; - const decoded = DefaultImportCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some string" supplied to "DefaultImportComments"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default array entry', () => { - const payload = null; - const decoded = DefaultImportCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([]); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.ts deleted file mode 100644 index dc8d18e7e11e6..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { importComment, ImportCommentsArray } from '../import_comment'; - -/** - * Types the DefaultImportCommentsArray as: - * - If null or undefined, then a default array of type ImportCommentsArray will be set - */ -export const DefaultImportCommentsArray = new t.Type< - ImportCommentsArray, - ImportCommentsArray, - unknown ->( - 'DefaultImportComments', - t.array(importComment).is, - (input, context): Either => - input == null ? t.success([]) : t.array(importComment).validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.test.ts deleted file mode 100644 index 69cdd841c0a5e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultNamespace } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_namespace', () => { - test('it should validate "single"', () => { - const payload = 'single'; - const decoded = DefaultNamespace.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate "agnostic"', () => { - const payload = 'agnostic'; - const decoded = DefaultNamespace.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it defaults to "single" if "undefined"', () => { - const payload = undefined; - const decoded = DefaultNamespace.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual('single'); - }); - - test('it defaults to "single" if "null"', () => { - const payload = null; - const decoded = DefaultNamespace.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual('single'); - }); - - test('it should FAIL validation if not "single" or "agnostic"', () => { - const payload = 'something else'; - const decoded = DefaultNamespace.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - `Invalid value "something else" supplied to "DefaultNamespace"`, - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.ts deleted file mode 100644 index 33f53c55b1986..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; - -export const namespaceType = t.keyof({ agnostic: null, single: null }); -export type NamespaceType = t.TypeOf; - -/** - * Types the DefaultNamespace as: - * - If null or undefined, then a default string/enumeration of "single" will be used. - */ -export const DefaultNamespace = new t.Type( - 'DefaultNamespace', - namespaceType.is, - (input, context): Either => - input == null ? t.success('single') : namespaceType.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.test.ts deleted file mode 100644 index 359674e57041e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultNamespaceArray, DefaultNamespaceArrayType } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_namespace_array', () => { - test('it should validate "null" single item as an array with a "single" value', () => { - const payload: DefaultNamespaceArrayType = null; - const decoded = DefaultNamespaceArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(['single']); - }); - - test('it should FAIL validation of numeric value', () => { - const payload = 5; - const decoded = DefaultNamespaceArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "DefaultNamespaceArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should validate "undefined" item as an array with a "single" value', () => { - const payload: DefaultNamespaceArrayType = undefined; - const decoded = DefaultNamespaceArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(['single']); - }); - - test('it should validate "single" as an array of a "single" value', () => { - const payload: DefaultNamespaceArrayType = 'single'; - const decoded = DefaultNamespaceArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([payload]); - }); - - test('it should validate "agnostic" as an array of a "agnostic" value', () => { - const payload: DefaultNamespaceArrayType = 'agnostic'; - const decoded = DefaultNamespaceArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([payload]); - }); - - test('it should validate "single,agnostic" as an array of 2 values of ["single", "agnostic"] values', () => { - const payload: DefaultNamespaceArrayType = 'agnostic,single'; - const decoded = DefaultNamespaceArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(['agnostic', 'single']); - }); - - test('it should validate 3 elements of "single,agnostic,single" as an array of 3 values of ["single", "agnostic", "single"] values', () => { - const payload: DefaultNamespaceArrayType = 'single,agnostic,single'; - const decoded = DefaultNamespaceArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(['single', 'agnostic', 'single']); - }); - - test('it should validate 3 elements of "single,agnostic, single" as an array of 3 values of ["single", "agnostic", "single"] values when there are spaces', () => { - const payload: DefaultNamespaceArrayType = ' single, agnostic, single '; - const decoded = DefaultNamespaceArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(['single', 'agnostic', 'single']); - }); - - test('it should FAIL validation when given 3 elements of "single,agnostic,junk" since the 3rd value is junk', () => { - const payload: DefaultNamespaceArrayType = 'single,agnostic,junk'; - const decoded = DefaultNamespaceArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "junk" supplied to "DefaultNamespaceArray"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.ts deleted file mode 100644 index 9692b8a2783d8..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { namespaceType } from '../default_namespace'; - -export const namespaceTypeArray = t.array(namespaceType); -export type NamespaceTypeArray = t.TypeOf; - -/** - * Types the DefaultNamespaceArray as: - * - If null or undefined, then a default string array of "single" will be used. - * - If it contains a string, then it is split along the commas and puts them into an array and validates it - */ -export const DefaultNamespaceArray = new t.Type< - NamespaceTypeArray, - string | undefined | null, - unknown ->( - 'DefaultNamespaceArray', - namespaceTypeArray.is, - (input, context): Either => { - if (input == null) { - return t.success(['single']); - } else if (typeof input === 'string') { - const commaSeparatedValues = input - .trim() - .split(',') - .map((value) => value.trim()); - return namespaceTypeArray.validate(commaSeparatedValues, context); - } - return t.failure(input, context); - }, - String -); - -export type DefaultNamespaceArrayType = t.OutputOf; -export type DefaultNamespaceArrayTypeDecoded = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.test.ts deleted file mode 100644 index aaffae53cecab..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { UpdateCommentsArray } from '../update_comment'; -import { DefaultUpdateCommentsArray } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getUpdateCommentsArrayMock } from '../update_comment/index.mock'; - -describe('default_update_comments_array', () => { - test('it should pass validation when supplied an empty array', () => { - const payload: UpdateCommentsArray = []; - const decoded = DefaultUpdateCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should pass validation when supplied an array of comments', () => { - const payload: UpdateCommentsArray = getUpdateCommentsArrayMock(); - const decoded = DefaultUpdateCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when supplied an array of numbers', () => { - const payload = [1]; - const decoded = DefaultUpdateCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "DefaultUpdateComments"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an array of strings', () => { - const payload = ['some string']; - const decoded = DefaultUpdateCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some string" supplied to "DefaultUpdateComments"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should return a default array entry', () => { - const payload = null; - const decoded = DefaultUpdateCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([]); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.ts deleted file mode 100644 index 47c0e562133df..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { updateCommentsArray, UpdateCommentsArray } from '../update_comment'; - -/** - * Types the DefaultUpdateComments as: - * - If null or undefined, then a default array of type UpdateCommentsArray will be set - */ -export const DefaultUpdateCommentsArray = new t.Type< - UpdateCommentsArray, - UpdateCommentsArray, - unknown ->( - 'DefaultUpdateComments', - updateCommentsArray.is, - (input, context): Either => - input == null ? t.success([]) : updateCommentsArray.validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/description/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/description/index.ts deleted file mode 100644 index 75fd7ac92ffcf..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/description/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const description = t.string; -export type Description = t.TypeOf; -export const descriptionOrUndefined = t.union([description, t.undefined]); -export type DescriptionOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/deserializer/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/deserializer/index.ts deleted file mode 100644 index c5489a946897e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/deserializer/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const deserializer = t.string; -export type Deserializer = t.TypeOf; -export const deserializerOrUndefined = t.union([deserializer, t.undefined]); -export type DeserializerOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts deleted file mode 100644 index bc091b1e33c35..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EndpointEntriesArray } from '.'; -import { getEndpointEntryMatchMock } from '../entry_match/index.mock'; -import { getEndpointEntryMatchAnyMock } from '../entry_match_any/index.mock'; -import { getEndpointEntryNestedMock } from '../entry_nested/index.mock'; -import { getEndpointEntryMatchWildcardMock } from '../entry_match_wildcard/index.mock'; - -export const getEndpointEntriesArrayMock = (): EndpointEntriesArray => [ - getEndpointEntryMatchMock(), - getEndpointEntryMatchAnyMock(), - getEndpointEntryNestedMock(), - getEndpointEntryMatchWildcardMock(), -]; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts deleted file mode 100644 index 574bf4276461b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEndpointEntryMatchMock } from '../entry_match/index.mock'; -import { - endpointEntriesArray, - nonEmptyEndpointEntriesArray, - NonEmptyEndpointEntriesArray, -} from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getEndpointEntryMatchAnyMock } from '../entry_match_any/index.mock'; -import { getEndpointEntryNestedMock } from '../entry_nested/index.mock'; -import { getEndpointEntriesArrayMock } from './index.mock'; -import { getEntryListMock } from '../../entries_list/index.mock'; -import { getEntryExistsMock } from '../../entries_exist/index.mock'; -import { getEndpointEntryMatchWildcardMock } from '../entry_match_wildcard/index.mock'; - -describe('Endpoint', () => { - describe('entriesArray', () => { - test('it should validate an array with match entry', () => { - const payload = [getEndpointEntryMatchMock()]; - const decoded = endpointEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array with match_any entry', () => { - const payload = [getEndpointEntryMatchAnyMock()]; - const decoded = endpointEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT validate an empty array', () => { - const payload: NonEmptyEndpointEntriesArray = []; - const decoded = nonEmptyEndpointEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "[]" supplied to "NonEmptyEndpointEntriesArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('type guard for nonEmptyEndpointNestedEntries should allow array of endpoint entries', () => { - const payload: NonEmptyEndpointEntriesArray = [getEndpointEntryMatchAnyMock()]; - const guarded = nonEmptyEndpointEntriesArray.is(payload); - expect(guarded).toBeTruthy(); - }); - - test('type guard for nonEmptyEndpointNestedEntries should disallow empty arrays', () => { - const payload: NonEmptyEndpointEntriesArray = []; - const guarded = nonEmptyEndpointEntriesArray.is(payload); - expect(guarded).toBeFalsy(); - }); - - test('it should NOT validate an array with exists entry', () => { - const payload = [getEntryExistsMock()]; - const decoded = endpointEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "exists" supplied to "type"', - 'Invalid value "undefined" supplied to "value"', - 'Invalid value "undefined" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT validate an array with list entry', () => { - const payload = [getEntryListMock()]; - const decoded = endpointEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "list" supplied to "type"', - 'Invalid value "undefined" supplied to "value"', - 'Invalid value "undefined" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should validate an array with nested entry', () => { - const payload = [getEndpointEntryNestedMock()]; - const decoded = endpointEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array with wildcard entry', () => { - const payload = [getEndpointEntryMatchWildcardMock()]; - const decoded = endpointEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array with all types of entries', () => { - const payload = getEndpointEntriesArrayMock(); - const decoded = endpointEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.ts deleted file mode 100644 index 992237161d06c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { endpointEntryMatch } from '../entry_match'; -import { endpointEntryMatchAny } from '../entry_match_any'; -import { endpointEntryNested } from '../entry_nested'; -import { endpointEntryMatchWildcard } from '../entry_match_wildcard'; - -export const endpointEntriesArray = t.array( - t.union([ - endpointEntryMatch, - endpointEntryMatchAny, - endpointEntryMatchWildcard, - endpointEntryNested, - ]) -); -export type EndpointEntriesArray = t.TypeOf; - -/** - * Types the nonEmptyEndpointEntriesArray as: - * - An array of entries of length 1 or greater - * - */ -export const nonEmptyEndpointEntriesArray = new t.Type< - EndpointEntriesArray, - EndpointEntriesArray, - unknown ->( - 'NonEmptyEndpointEntriesArray', - (u: unknown): u is EndpointEntriesArray => endpointEntriesArray.is(u) && u.length > 0, - (input, context): Either => { - if (Array.isArray(input) && input.length === 0) { - return t.failure(input, context); - } else { - return endpointEntriesArray.validate(input, context); - } - }, - t.identity -); - -export type NonEmptyEndpointEntriesArray = t.OutputOf; -export type NonEmptyEndpointEntriesArrayDecoded = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.mock.ts deleted file mode 100644 index 76305cf70c585..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EndpointEntryMatch } from '.'; -import { ENTRY_VALUE, FIELD, MATCH, OPERATOR } from '../../../constants/index.mock'; - -export const getEndpointEntryMatchMock = (): EndpointEntryMatch => ({ - field: FIELD, - operator: OPERATOR, - type: MATCH, - value: ENTRY_VALUE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.test.ts deleted file mode 100644 index 5c20b697b3bf5..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEndpointEntryMatchMock } from './index.mock'; -import { EndpointEntryMatch, endpointEntryMatch } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getEntryMatchMock } from '../../entry_match/index.mock'; - -describe('endpointEntryMatch', () => { - test('it should validate an entry', () => { - const payload = getEndpointEntryMatchMock(); - const decoded = endpointEntryMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT validate when "operator" is "excluded"', () => { - // Use the generic entry mock so we can test operator: excluded - const payload = getEntryMatchMock(); - payload.operator = 'excluded'; - const decoded = endpointEntryMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "excluded" supplied to "operator"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "field" is empty string', () => { - const payload: Omit & { field: string } = { - ...getEndpointEntryMatchMock(), - field: '', - }; - const decoded = endpointEntryMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "value" is not string', () => { - const payload: Omit & { value: string[] } = { - ...getEndpointEntryMatchMock(), - value: ['some value'], - }; - const decoded = endpointEntryMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "["some value"]" supplied to "value"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "value" is empty string', () => { - const payload: Omit & { value: string } = { - ...getEndpointEntryMatchMock(), - value: '', - }; - const decoded = endpointEntryMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "type" is not "match"', () => { - const payload: Omit & { type: string } = { - ...getEndpointEntryMatchMock(), - type: 'match_any', - }; - const decoded = endpointEntryMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "match_any" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: EndpointEntryMatch & { - extraKey?: string; - } = getEndpointEntryMatchMock(); - payload.extraKey = 'some value'; - const decoded = endpointEntryMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEntryMatchMock()); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.ts deleted file mode 100644 index 5ae0258ebfb79..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString, operatorIncluded } from '@kbn/securitysolution-io-ts-types'; - -export const endpointEntryMatch = t.exact( - t.type({ - field: NonEmptyString, - operator: operatorIncluded, - type: t.keyof({ match: null }), - value: NonEmptyString, - }) -); -export type EndpointEntryMatch = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.mock.ts deleted file mode 100644 index b3bfffd4daf97..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ENTRY_VALUE, FIELD, MATCH_ANY, OPERATOR } from '../../../constants/index.mock'; -import { EndpointEntryMatchAny } from '.'; - -export const getEndpointEntryMatchAnyMock = (): EndpointEntryMatchAny => ({ - field: FIELD, - operator: OPERATOR, - type: MATCH_ANY, - value: [ENTRY_VALUE], -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.test.ts deleted file mode 100644 index e121eed769ea9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEndpointEntryMatchAnyMock } from './index.mock'; -import { EndpointEntryMatchAny, endpointEntryMatchAny } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getEntryMatchAnyMock } from '../../entry_match_any/index.mock'; - -describe('endpointEntryMatchAny', () => { - test('it should validate an entry', () => { - const payload = getEndpointEntryMatchAnyMock(); - const decoded = endpointEntryMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT validate when operator is "excluded"', () => { - // Use the generic entry mock so we can test operator: excluded - const payload = getEntryMatchAnyMock(); - payload.operator = 'excluded'; - const decoded = endpointEntryMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "excluded" supplied to "operator"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when field is empty string', () => { - const payload: Omit & { field: string } = { - ...getEndpointEntryMatchAnyMock(), - field: '', - }; - const decoded = endpointEntryMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when value is empty array', () => { - const payload: Omit & { value: string[] } = { - ...getEndpointEntryMatchAnyMock(), - value: [], - }; - const decoded = endpointEntryMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "[]" supplied to "value"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when value is not string array', () => { - const payload: Omit & { value: string } = { - ...getEndpointEntryMatchAnyMock(), - value: 'some string', - }; - const decoded = endpointEntryMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some string" supplied to "value"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "type" is not "match_any"', () => { - const payload: Omit & { type: string } = { - ...getEndpointEntryMatchAnyMock(), - type: 'match', - }; - const decoded = endpointEntryMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: EndpointEntryMatchAny & { - extraKey?: string; - } = getEndpointEntryMatchAnyMock(); - payload.extraKey = 'some extra key'; - const decoded = endpointEntryMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEntryMatchAnyMock()); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.ts deleted file mode 100644 index d639f4481d4d3..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { - NonEmptyString, - nonEmptyOrNullableStringArray, - operatorIncluded, -} from '@kbn/securitysolution-io-ts-types'; - -export const endpointEntryMatchAny = t.exact( - t.type({ - field: NonEmptyString, - operator: operatorIncluded, - type: t.keyof({ match_any: null }), - value: nonEmptyOrNullableStringArray, - }) -); -export type EndpointEntryMatchAny = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts deleted file mode 100644 index f1b5c7e7421af..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ENTRY_VALUE, FIELD, OPERATOR, WILDCARD } from '../../../constants/index.mock'; -import { EndpointEntryMatchWildcard } from '.'; - -export const getEndpointEntryMatchWildcardMock = (): EndpointEntryMatchWildcard => ({ - field: FIELD, - operator: OPERATOR, - type: WILDCARD, - value: ENTRY_VALUE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.test.ts deleted file mode 100644 index 025994afcd9ef..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEndpointEntryMatchWildcardMock } from './index.mock'; -import { EndpointEntryMatchWildcard, endpointEntryMatchWildcard } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getEntryMatchWildcardMock } from '../../entry_match_wildcard/index.mock'; - -describe('endpointEntryMatchWildcard', () => { - test('it should validate an entry', () => { - const payload = getEndpointEntryMatchWildcardMock(); - const decoded = endpointEntryMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when "operator" is "excluded"', () => { - const payload = getEntryMatchWildcardMock(); - payload.operator = 'excluded'; - const decoded = endpointEntryMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when "field" is empty string', () => { - const payload: Omit & { field: string } = { - ...getEndpointEntryMatchWildcardMock(), - field: '', - }; - const decoded = endpointEntryMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "value" is not string', () => { - const payload: Omit & { value: string[] } = { - ...getEndpointEntryMatchWildcardMock(), - value: ['some value'], - }; - const decoded = endpointEntryMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "["some value"]" supplied to "value"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "value" is empty string', () => { - const payload: Omit & { value: string } = { - ...getEndpointEntryMatchWildcardMock(), - value: '', - }; - const decoded = endpointEntryMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "type" is not "wildcard"', () => { - const payload: Omit & { type: string } = { - ...getEndpointEntryMatchWildcardMock(), - type: 'match', - }; - const decoded = endpointEntryMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: EndpointEntryMatchWildcard & { - extraKey?: string; - } = getEndpointEntryMatchWildcardMock(); - payload.extraKey = 'some value'; - const decoded = endpointEntryMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEntryMatchWildcardMock()); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.ts deleted file mode 100644 index b42f6245ea28d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { - NonEmptyString, - operatorExcluded, - operatorIncluded, -} from '@kbn/securitysolution-io-ts-types'; - -export const endpointEntryMatchWildcard = t.exact( - t.type({ - field: NonEmptyString, - operator: t.union([operatorIncluded, operatorExcluded]), - type: t.keyof({ wildcard: null }), - value: NonEmptyString, - }) -); -export type EndpointEntryMatchWildcard = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.mock.ts deleted file mode 100644 index 44c5f8db5f6e7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.mock.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EndpointEntryNested } from '.'; -import { FIELD, NESTED } from '../../../constants/index.mock'; -import { getEndpointEntryMatchMock } from '../entry_match/index.mock'; -import { getEndpointEntryMatchAnyMock } from '../entry_match_any/index.mock'; - -export const getEndpointEntryNestedMock = (): EndpointEntryNested => ({ - entries: [getEndpointEntryMatchMock(), getEndpointEntryMatchAnyMock()], - field: FIELD, - type: NESTED, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.test.ts deleted file mode 100644 index c062deb88af81..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { EndpointEntryNested, endpointEntryNested } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getEndpointEntryNestedMock } from './index.mock'; -import { getEndpointEntryMatchAnyMock } from '../entry_match_any/index.mock'; -import { - nonEmptyEndpointNestedEntriesArray, - NonEmptyEndpointNestedEntriesArray, -} from '../non_empty_nested_entries_array'; -import { getEndpointEntryMatchMock } from '../entry_match/index.mock'; -import { getEntryExistsMock } from '../../entries_exist/index.mock'; - -describe('endpointEntryNested', () => { - test('it should validate a nested entry', () => { - const payload = getEndpointEntryNestedMock(); - const decoded = endpointEntryNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when "type" is not "nested"', () => { - const payload: Omit & { type: 'match' } = { - ...getEndpointEntryNestedMock(), - type: 'match', - }; - const decoded = endpointEntryNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "field" is empty string', () => { - const payload: Omit & { - field: string; - } = { ...getEndpointEntryNestedMock(), field: '' }; - const decoded = endpointEntryNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "field" is not a string', () => { - const payload: Omit & { - field: number; - } = { ...getEndpointEntryNestedMock(), field: 1 }; - const decoded = endpointEntryNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "entries" is not an array', () => { - const payload: Omit & { - entries: string; - } = { ...getEndpointEntryNestedMock(), entries: 'im a string' }; - const decoded = endpointEntryNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "im a string" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should validate when "entries" contains an entry item that is type "match"', () => { - const payload = { ...getEndpointEntryNestedMock(), entries: [getEndpointEntryMatchAnyMock()] }; - const decoded = endpointEntryNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual({ - entries: [ - { - field: 'host.name', - operator: 'included', - type: 'match_any', - value: ['some host name'], - }, - ], - field: 'host.name', - type: 'nested', - }); - }); - - test('it should NOT validate when "entries" contains an entry item that is type "exists"', () => { - const payload = { ...getEndpointEntryNestedMock(), entries: [getEntryExistsMock()] }; - const decoded = endpointEntryNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "exists" supplied to "entries,type"', - 'Invalid value "undefined" supplied to "entries,value"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: EndpointEntryNested & { - extraKey?: string; - } = getEndpointEntryNestedMock(); - payload.extraKey = 'some extra key'; - const decoded = endpointEntryNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEndpointEntryNestedMock()); - }); - - test('type guard for nonEmptyEndpointNestedEntries should allow array of endpoint entries', () => { - const payload: NonEmptyEndpointNestedEntriesArray = [ - getEndpointEntryMatchMock(), - getEndpointEntryMatchAnyMock(), - ]; - const guarded = nonEmptyEndpointNestedEntriesArray.is(payload); - expect(guarded).toBeTruthy(); - }); - - test('type guard for nonEmptyEndpointNestedEntries should disallow empty arrays', () => { - const payload: NonEmptyEndpointNestedEntriesArray = []; - const guarded = nonEmptyEndpointNestedEntriesArray.is(payload); - expect(guarded).toBeFalsy(); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.ts deleted file mode 100644 index 6625c1dfeaf59..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -import { nonEmptyEndpointNestedEntriesArray } from '../non_empty_nested_entries_array'; - -export const endpointEntryNested = t.exact( - t.type({ - entries: nonEmptyEndpointNestedEntriesArray, - field: NonEmptyString, - type: t.keyof({ nested: null }), - }) -); -export type EndpointEntryNested = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/index.ts deleted file mode 100644 index fb42cc8ee4686..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './entries'; -export * from './non_empty_nested_entries_array'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/non_empty_nested_entries_array/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/non_empty_nested_entries_array/index.ts deleted file mode 100644 index 9bcfccae97b31..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/non_empty_nested_entries_array/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { endpointEntryMatch } from '../entry_match'; -import { endpointEntryMatchAny } from '../entry_match_any'; - -export const endpointNestedEntriesArray = t.array( - t.union([endpointEntryMatch, endpointEntryMatchAny]) -); -export type EndpointNestedEntriesArray = t.TypeOf; - -/** - * Types the nonEmptyNestedEntriesArray as: - * - An array of entries of length 1 or greater - * - */ -export const nonEmptyEndpointNestedEntriesArray = new t.Type< - EndpointNestedEntriesArray, - EndpointNestedEntriesArray, - unknown ->( - 'NonEmptyEndpointNestedEntriesArray', - (u: unknown): u is EndpointNestedEntriesArray => endpointNestedEntriesArray.is(u) && u.length > 0, - (input, context): Either => { - if (Array.isArray(input) && input.length === 0) { - return t.failure(input, context); - } else { - return endpointNestedEntriesArray.validate(input, context); - } - }, - t.identity -); - -export type NonEmptyEndpointNestedEntriesArray = t.OutputOf< - typeof nonEmptyEndpointNestedEntriesArray ->; -export type NonEmptyEndpointNestedEntriesArrayDecoded = t.TypeOf< - typeof nonEmptyEndpointNestedEntriesArray ->; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.mock.ts deleted file mode 100644 index 5b8c802c94a38..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.mock.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EntriesArray } from '.'; -import { getEntryExistsMock } from '../entries_exist/index.mock'; -import { getEntryListMock } from '../entries_list/index.mock'; -import { getEntryMatchMock } from '../entry_match/index.mock'; -import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; -import { getEntryNestedMock } from '../entry_nested/index.mock'; - -export const getListAndNonListEntriesArrayMock = (): EntriesArray => [ - getEntryMatchMock(), - getEntryMatchAnyMock(), - getEntryListMock(), - getEntryExistsMock(), - getEntryNestedMock(), -]; - -export const getListEntriesArrayMock = (): EntriesArray => [getEntryListMock(), getEntryListMock()]; - -export const getEntriesArrayMock = (): EntriesArray => [ - getEntryMatchMock(), - getEntryMatchAnyMock(), - getEntryExistsMock(), - getEntryNestedMock(), -]; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.test.ts deleted file mode 100644 index 73553be78b9a1..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.test.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEntryMatchMock } from '../entry_match/index.mock'; -import { entriesArray, entriesArrayOrUndefined, entry } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; -import { getEntryExistsMock } from '../entries_exist/index.mock'; -import { getEntryListMock } from '../entries_list/index.mock'; -import { getEntryNestedMock } from '../entry_nested/index.mock'; -import { getEntriesArrayMock } from './index.mock'; - -describe('Entries', () => { - describe('entry', () => { - test('it should validate a match entry', () => { - const payload = getEntryMatchMock(); - const decoded = entry.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate a match_any entry', () => { - const payload = getEntryMatchAnyMock(); - const decoded = entry.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate a exists entry', () => { - const payload = getEntryExistsMock(); - const decoded = entry.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate a list entry', () => { - const payload = getEntryListMock(); - const decoded = entry.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation of nested entry', () => { - const payload = getEntryNestedMock(); - const decoded = entry.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "operator"', - 'Invalid value "nested" supplied to "type"', - 'Invalid value "undefined" supplied to "value"', - 'Invalid value "undefined" supplied to "list"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('entriesArray', () => { - test('it should validate an array with match entry', () => { - const payload = [getEntryMatchMock()]; - const decoded = entriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array with match_any entry', () => { - const payload = [getEntryMatchAnyMock()]; - const decoded = entriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array with exists entry', () => { - const payload = [getEntryExistsMock()]; - const decoded = entriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array with list entry', () => { - const payload = [getEntryListMock()]; - const decoded = entriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array with nested entry', () => { - const payload = [getEntryNestedMock()]; - const decoded = entriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array with all types of entries', () => { - const payload = [...getEntriesArrayMock()]; - const decoded = entriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - }); - - describe('entriesArrayOrUndefined', () => { - test('it should validate undefined', () => { - const payload = undefined; - const decoded = entriesArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array with nested entry', () => { - const payload = [getEntryNestedMock()]; - const decoded = entriesArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.ts deleted file mode 100644 index f2dbbd91dfceb..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { entriesExists } from '../entries_exist'; -import { entriesList } from '../entries_list'; -import { entriesMatch } from '../entry_match'; -import { entriesMatchAny } from '../entry_match_any'; -import { entriesMatchWildcard } from '../entry_match_wildcard'; -import { entriesNested } from '../entry_nested'; - -// NOTE: Type nested is not included here to denote it's non-recursive nature. -// So a nested entry is really just a collection of `Entry` types. -export const entry = t.union([ - entriesMatch, - entriesMatchAny, - entriesList, - entriesExists, - entriesMatchWildcard, -]); -export type Entry = t.TypeOf; - -export const entriesArray = t.array( - t.union([ - entriesMatch, - entriesMatchAny, - entriesList, - entriesExists, - entriesNested, - entriesMatchWildcard, - ]) -); -export type EntriesArray = t.TypeOf; - -export const entriesArrayOrUndefined = t.union([entriesArray, t.undefined]); -export type EntriesArrayOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.mock.ts deleted file mode 100644 index 3a588ec9cc7ba..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.mock.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EntryExists } from '.'; -import { EXISTS, FIELD, OPERATOR } from '../../constants/index.mock'; - -export const getEntryExistsMock = (): EntryExists => ({ - field: FIELD, - operator: OPERATOR, - type: EXISTS, -}); - -export const getEntryExistsExcludedMock = (): EntryExists => ({ - ...getEntryExistsMock(), - operator: 'excluded', -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.test.ts deleted file mode 100644 index 8ebf60ebc19f1..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEntryExistsMock } from './index.mock'; -import { entriesExists, EntryExists } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('entriesExists', () => { - test('it should validate an entry', () => { - const payload = getEntryExistsMock(); - const decoded = entriesExists.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when "operator" is "included"', () => { - const payload = getEntryExistsMock(); - const decoded = entriesExists.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when "operator" is "excluded"', () => { - const payload = getEntryExistsMock(); - payload.operator = 'excluded'; - const decoded = entriesExists.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when "field" is empty string', () => { - const payload: Omit & { field: string } = { - ...getEntryExistsMock(), - field: '', - }; - const decoded = entriesExists.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: EntryExists & { - extraKey?: string; - } = getEntryExistsMock(); - payload.extraKey = 'some extra key'; - const decoded = entriesExists.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEntryExistsMock()); - }); - - test('it should FAIL validation when "type" is not "exists"', () => { - const payload: Omit & { type: string } = { - ...getEntryExistsMock(), - type: 'match', - }; - const decoded = entriesExists.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.ts deleted file mode 100644 index 460030dcc951b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -import { listOperator as operator } from '../list_operator'; - -export const entriesExists = t.exact( - t.type({ - field: NonEmptyString, - operator, - type: t.keyof({ exists: null }), - }) -); -export type EntryExists = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.mock.ts deleted file mode 100644 index 06e006ed661ba..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EntryList } from '.'; -import { FIELD, LIST, LIST_ID, OPERATOR, TYPE } from '../../constants/index.mock'; - -export const getEntryListMock = (): EntryList => ({ - field: FIELD, - list: { id: LIST_ID, type: TYPE }, - operator: OPERATOR, - type: LIST, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.test.ts deleted file mode 100644 index eb047a07f08dd..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEntryListMock } from './index.mock'; -import { entriesList, EntryList } from '.'; - -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('entriesList', () => { - test('it should validate an entry', () => { - const payload = getEntryListMock(); - const decoded = entriesList.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when operator is "included"', () => { - const payload = getEntryListMock(); - const decoded = entriesList.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when "operator" is "excluded"', () => { - const payload = getEntryListMock(); - payload.operator = 'excluded'; - const decoded = entriesList.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when "list" is not expected value', () => { - const payload: Omit & { list: string } = { - ...getEntryListMock(), - list: 'someListId', - }; - const decoded = entriesList.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "someListId" supplied to "list"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "list.id" is empty string', () => { - const payload: Omit & { list: { id: string; type: 'ip' } } = { - ...getEntryListMock(), - list: { id: '', type: 'ip' }, - }; - const decoded = entriesList.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "list,id"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "type" is not "lists"', () => { - const payload: Omit & { type: 'match_any' } = { - ...getEntryListMock(), - type: 'match_any', - }; - const decoded = entriesList.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "match_any" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: EntryList & { - extraKey?: string; - } = getEntryListMock(); - payload.extraKey = 'some extra key'; - const decoded = entriesList.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEntryListMock()); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.ts deleted file mode 100644 index f55a3f056218a..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; - -import { type } from '../type'; -import { listOperator as operator } from '../list_operator'; - -export const entriesList = t.exact( - t.type({ - field: NonEmptyString, - list: t.exact(t.type({ id: NonEmptyString, type })), - operator, - type: t.keyof({ list: null }), - }) -); -export type EntryList = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.mock.ts deleted file mode 100644 index 9e09661c29456..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.mock.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EntryMatch } from '.'; -import { ENTRY_VALUE, FIELD, MATCH, OPERATOR } from '../../constants/index.mock'; - -export const getEntryMatchMock = (): EntryMatch => ({ - field: FIELD, - operator: OPERATOR, - type: MATCH, - value: ENTRY_VALUE, -}); - -export const getEntryMatchExcludeMock = (): EntryMatch => ({ - ...getEntryMatchMock(), - operator: 'excluded', -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.test.ts deleted file mode 100644 index f2f8dbb8998f3..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEntryMatchMock } from './index.mock'; -import { entriesMatch, EntryMatch } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('entriesMatch', () => { - test('it should validate an entry', () => { - const payload = getEntryMatchMock(); - const decoded = entriesMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when operator is "included"', () => { - const payload = getEntryMatchMock(); - const decoded = entriesMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when "operator" is "excluded"', () => { - const payload = getEntryMatchMock(); - payload.operator = 'excluded'; - const decoded = entriesMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when "field" is empty string', () => { - const payload: Omit & { field: string } = { - ...getEntryMatchMock(), - field: '', - }; - const decoded = entriesMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "value" is not string', () => { - const payload: Omit & { value: string[] } = { - ...getEntryMatchMock(), - value: ['some value'], - }; - const decoded = entriesMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "["some value"]" supplied to "value"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "value" is empty string', () => { - const payload: Omit & { value: string } = { - ...getEntryMatchMock(), - value: '', - }; - const decoded = entriesMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "type" is not "match"', () => { - const payload: Omit & { type: string } = { - ...getEntryMatchMock(), - type: 'match_any', - }; - const decoded = entriesMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "match_any" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: EntryMatch & { - extraKey?: string; - } = getEntryMatchMock(); - payload.extraKey = 'some value'; - const decoded = entriesMatch.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEntryMatchMock()); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.ts deleted file mode 100644 index 17bf0ab5b89e6..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -import { listOperator as operator } from '../list_operator'; - -export const entriesMatch = t.exact( - t.type({ - field: NonEmptyString, - operator, - type: t.keyof({ match: null }), - value: NonEmptyString, - }) -); -export type EntryMatch = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.mock.ts deleted file mode 100644 index 7a5c4c57fa32f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.mock.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EntryMatchAny } from '.'; -import { ENTRY_VALUE, FIELD, MATCH_ANY, OPERATOR } from '../../constants/index.mock'; - -export const getEntryMatchAnyMock = (): EntryMatchAny => ({ - field: FIELD, - operator: OPERATOR, - type: MATCH_ANY, - value: [ENTRY_VALUE], -}); - -export const getEntryMatchAnyExcludeMock = (): EntryMatchAny => ({ - ...getEntryMatchAnyMock(), - operator: 'excluded', - value: [ENTRY_VALUE, 'some other host name'], -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.test.ts deleted file mode 100644 index 3e4752f395088..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEntryMatchAnyMock } from './index.mock'; -import { entriesMatchAny, EntryMatchAny } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('entriesMatchAny', () => { - test('it should validate an entry', () => { - const payload = getEntryMatchAnyMock(); - const decoded = entriesMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when operator is "included"', () => { - const payload = getEntryMatchAnyMock(); - const decoded = entriesMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when operator is "excluded"', () => { - const payload = getEntryMatchAnyMock(); - payload.operator = 'excluded'; - const decoded = entriesMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when field is empty string', () => { - const payload: Omit & { field: string } = { - ...getEntryMatchAnyMock(), - field: '', - }; - const decoded = entriesMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when value is empty array', () => { - const payload: Omit & { value: string[] } = { - ...getEntryMatchAnyMock(), - value: [], - }; - const decoded = entriesMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "[]" supplied to "value"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when value is not string array', () => { - const payload: Omit & { value: string } = { - ...getEntryMatchAnyMock(), - value: 'some string', - }; - const decoded = entriesMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some string" supplied to "value"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "type" is not "match_any"', () => { - const payload: Omit & { type: string } = { - ...getEntryMatchAnyMock(), - type: 'match', - }; - const decoded = entriesMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: EntryMatchAny & { - extraKey?: string; - } = getEntryMatchAnyMock(); - payload.extraKey = 'some extra key'; - const decoded = entriesMatchAny.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEntryMatchAnyMock()); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.ts deleted file mode 100644 index be08fb370abdc..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { NonEmptyString, nonEmptyOrNullableStringArray } from '@kbn/securitysolution-io-ts-types'; -import { listOperator as operator } from '../list_operator'; - -export const entriesMatchAny = t.exact( - t.type({ - field: NonEmptyString, - operator, - type: t.keyof({ match_any: null }), - value: nonEmptyOrNullableStringArray, - }) -); -export type EntryMatchAny = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.mock.ts deleted file mode 100644 index 6dc33289d22db..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.mock.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EntryMatchWildcard } from '.'; -import { ENTRY_VALUE, FIELD, OPERATOR, WILDCARD } from '../../constants/index.mock'; - -export const getEntryMatchWildcardMock = (): EntryMatchWildcard => ({ - field: FIELD, - operator: OPERATOR, - type: WILDCARD, - value: ENTRY_VALUE, -}); - -export const getEntryMatchWildcardExcludeMock = (): EntryMatchWildcard => ({ - ...getEntryMatchWildcardMock(), - operator: 'excluded', -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.test.ts deleted file mode 100644 index a84996a6c1050..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEntryMatchWildcardMock } from './index.mock'; -import { entriesMatchWildcard, EntryMatchWildcard } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('entriesMatchWildcard', () => { - test('it should validate an entry', () => { - const payload = getEntryMatchWildcardMock(); - const decoded = entriesMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when operator is "included"', () => { - const payload = getEntryMatchWildcardMock(); - const decoded = entriesMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when "operator" is "excluded"', () => { - const payload = getEntryMatchWildcardMock(); - payload.operator = 'excluded'; - const decoded = entriesMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when "field" is empty string', () => { - const payload: Omit & { field: string } = { - ...getEntryMatchWildcardMock(), - field: '', - }; - const decoded = entriesMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "value" is not string', () => { - const payload: Omit & { value: string[] } = { - ...getEntryMatchWildcardMock(), - value: ['some value'], - }; - const decoded = entriesMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "["some value"]" supplied to "value"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "value" is empty string', () => { - const payload: Omit & { value: string } = { - ...getEntryMatchWildcardMock(), - value: '', - }; - const decoded = entriesMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "type" is not "wildcard"', () => { - const payload: Omit & { type: string } = { - ...getEntryMatchWildcardMock(), - type: 'match', - }; - const decoded = entriesMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: EntryMatchWildcard & { - extraKey?: string; - } = getEntryMatchWildcardMock(); - payload.extraKey = 'some value'; - const decoded = entriesMatchWildcard.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEntryMatchWildcardMock()); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.ts deleted file mode 100644 index 17afe342961c2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -import { listOperator as operator } from '../list_operator'; - -export const entriesMatchWildcard = t.exact( - t.type({ - field: NonEmptyString, - operator, - type: t.keyof({ wildcard: null }), - value: NonEmptyString, - }) -); -export type EntryMatchWildcard = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.mock.ts deleted file mode 100644 index 34d687502e245..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.mock.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EntryNested } from '.'; -import { NESTED, NESTED_FIELD } from '../../constants/index.mock'; -import { getEntryExistsMock } from '../entries_exist/index.mock'; -import { getEntryMatchExcludeMock, getEntryMatchMock } from '../entry_match/index.mock'; -import { getEntryMatchAnyExcludeMock, getEntryMatchAnyMock } from '../entry_match_any/index.mock'; - -export const getEntryNestedMock = (): EntryNested => ({ - entries: [getEntryMatchMock(), getEntryMatchAnyMock()], - field: NESTED_FIELD, - type: NESTED, -}); - -export const getEntryNestedExcludeMock = (): EntryNested => ({ - ...getEntryNestedMock(), - entries: [getEntryMatchExcludeMock(), getEntryMatchAnyExcludeMock()], -}); - -export const getEntryNestedMixedEntries = (): EntryNested => ({ - ...getEntryNestedMock(), - entries: [getEntryMatchMock(), getEntryMatchAnyExcludeMock(), getEntryExistsMock()], -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.test.ts deleted file mode 100644 index cfd43c4c09935..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEntryNestedMock } from './index.mock'; -import { entriesNested, EntryNested } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; -import { getEntryExistsMock } from '../entries_exist/index.mock'; - -describe('entriesNested', () => { - test('it should validate a nested entry', () => { - const payload = getEntryNestedMock(); - const decoded = entriesNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when "type" is not "nested"', () => { - const payload: Omit & { type: 'match' } = { - ...getEntryNestedMock(), - type: 'match', - }; - const decoded = entriesNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "field" is empty string', () => { - const payload: Omit & { - field: string; - } = { ...getEntryNestedMock(), field: '' }; - const decoded = entriesNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "field" is not a string', () => { - const payload: Omit & { - field: number; - } = { ...getEntryNestedMock(), field: 1 }; - const decoded = entriesNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "field"']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when "entries" is not a an array', () => { - const payload: Omit & { - entries: string; - } = { ...getEntryNestedMock(), entries: 'im a string' }; - const decoded = entriesNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "im a string" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should validate when "entries" contains an entry item that is type "match"', () => { - const payload = { ...getEntryNestedMock(), entries: [getEntryMatchAnyMock()] }; - const decoded = entriesNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual({ - entries: [ - { - field: 'host.name', - operator: 'included', - type: 'match_any', - value: ['some host name'], - }, - ], - field: 'parent.field', - type: 'nested', - }); - }); - - test('it should validate when "entries" contains an entry item that is type "exists"', () => { - const payload = { ...getEntryNestedMock(), entries: [getEntryExistsMock()] }; - const decoded = entriesNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual({ - entries: [ - { - field: 'host.name', - operator: 'included', - type: 'exists', - }, - ], - field: 'parent.field', - type: 'nested', - }); - }); - - test('it should strip out extra keys', () => { - const payload: EntryNested & { - extraKey?: string; - } = getEntryNestedMock(); - payload.extraKey = 'some extra key'; - const decoded = entriesNested.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getEntryNestedMock()); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.ts deleted file mode 100644 index 8b19fee9fb5cf..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -import { nonEmptyNestedEntriesArray } from '../non_empty_nested_entries_array'; - -export const entriesNested = t.exact( - t.type({ - entries: nonEmptyNestedEntriesArray, - field: NonEmptyString, - type: t.keyof({ nested: null }), - }) -); -export type EntryNested = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.mock.ts deleted file mode 100644 index 15cdd79dc2e9b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.mock.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ExportExceptionDetails } from '.'; - -export interface ExportExceptionDetailsMock { - listCount?: number; - missingListsCount?: number; - missingLists?: Array>; - itemCount?: number; - missingItemCount?: number; - missingItems?: Array>; -} - -export const getExceptionExportDetailsMock = ( - details?: ExportExceptionDetailsMock -): ExportExceptionDetails => ({ - exported_exception_list_count: details?.listCount ?? 0, - exported_exception_list_item_count: details?.itemCount ?? 0, - missing_exception_list_item_count: details?.missingItemCount ?? 0, - missing_exception_list_items: details?.missingItems ?? [], - missing_exception_lists: details?.missingLists ?? [], - missing_exception_lists_count: details?.missingListsCount ?? 0, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.test.ts deleted file mode 100644 index c9b1a4767e573..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getExceptionExportDetailsMock } from './index.mock'; -import { exportExceptionDetailsSchema, ExportExceptionDetails } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('exportExceptionDetails', () => { - test('it should validate export meta', () => { - const payload = getExceptionExportDetailsMock(); - const decoded = exportExceptionDetailsSchema.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should strip out extra keys', () => { - const payload: ExportExceptionDetails & { - extraKey?: string; - } = getExceptionExportDetailsMock(); - payload.extraKey = 'some extra key'; - const decoded = exportExceptionDetailsSchema.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getExceptionExportDetailsMock()); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.ts deleted file mode 100644 index 9e4ff134d6e9f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; - -export const exportExceptionDetails = { - exported_exception_list_count: t.number, - exported_exception_list_item_count: t.number, - missing_exception_list_item_count: t.number, - missing_exception_list_items: t.array( - t.exact( - t.type({ - item_id: NonEmptyString, - }) - ) - ), - missing_exception_lists: t.array( - t.exact( - t.type({ - list_id: NonEmptyString, - }) - ) - ), - missing_exception_lists_count: t.number, -}; - -export const exportExceptionDetailsSchema = t.exact(t.type(exportExceptionDetails)); - -export type ExportExceptionDetails = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.test.ts deleted file mode 100644 index 2c6aae8a56937..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { exceptionListType, ExceptionListTypeEnum } from '.'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('exceptionListType', () => { - test('it should validate for "detection"', () => { - const payload = 'detection'; - const decoded = exceptionListType.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate for "rule_default"', () => { - const payload = 'rule_default'; - const decoded = exceptionListType.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate for "endpoint"', () => { - const payload = 'endpoint'; - const decoded = exceptionListType.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should contain same amount of keys as enum', () => { - // Might seem like a weird test, but its meant to - // ensure that if exceptionListType is updated, you - // also update the ExceptionListTypeEnum, a workaround - // for io-ts not yet supporting enums - // https://github.com/gcanti/io-ts/issues/67 - const keys = Object.keys(exceptionListType.keys).sort().join(',').toLowerCase(); - const enumKeys = Object.keys(ExceptionListTypeEnum).sort().join(',').toLowerCase(); - - expect(keys).toEqual(enumKeys); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.ts deleted file mode 100644 index db7633705ac5b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const exceptionListType = t.keyof({ - detection: null, - rule_default: null, - endpoint: null, - endpoint_trusted_apps: null, - endpoint_events: null, - endpoint_host_isolation_exceptions: null, - endpoint_blocklists: null, -}); -export const exceptionListTypeOrUndefined = t.union([exceptionListType, t.undefined]); -export type ExceptionListType = t.TypeOf; -export type ExceptionListTypeOrUndefined = t.TypeOf; -export enum ExceptionListTypeEnum { - DETECTION = 'detection', // shared exception list type - RULE_DEFAULT = 'rule_default', // rule default, cannot be shared - ENDPOINT = 'endpoint', - ENDPOINT_TRUSTED_APPS = 'endpoint', - ENDPOINT_EVENTS = 'endpoint_events', - ENDPOINT_HOST_ISOLATION_EXCEPTIONS = 'endpoint_host_isolation_exceptions', - ENDPOINT_BLOCKLISTS = 'endpoint_blocklists', -} diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list_item_type/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list_item_type/index.ts deleted file mode 100644 index 5e124b9f923d9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list_item_type/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const exceptionListItemType = t.keyof({ simple: null }); -export const exceptionListItemTypeOrUndefined = t.union([exceptionListItemType, t.undefined]); -export type ExceptionListItemType = t.TypeOf; -export type ExceptionListItemTypeOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/expire_time/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/expire_time/index.ts deleted file mode 100644 index 4e8184d4e6ce9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/expire_time/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { IsoDateString } from '@kbn/securitysolution-io-ts-types'; - -export const expireTime = IsoDateString; -export const expireTimeOrUndefined = t.union([expireTime, t.undefined]); -export type ExpireTimeOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/file/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/file/index.ts deleted file mode 100644 index f569d42c41f17..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/file/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const file = t.object; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/filter/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/filter/index.ts deleted file mode 100644 index 70d526eaefbe5..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/filter/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const filter = t.string; -export type Filter = t.TypeOf; -export const filterOrUndefined = t.union([filter, t.undefined]); -export type FilterOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/id/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/id/index.ts deleted file mode 100644 index c9f35b36ee577..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/id/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; - -export const id = NonEmptyString; -export type Id = t.TypeOf; -export const idOrUndefined = t.union([id, t.undefined]); -export type IdOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/immutable/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/immutable/index.ts deleted file mode 100644 index 9bdb50647abd2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/immutable/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const immutable = t.boolean; -export type Immutable = t.TypeOf; -export const immutableOrUndefined = t.union([immutable, t.undefined]); -export type ImmutableOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.test.ts deleted file mode 100644 index 50121086c1411..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getCommentsArrayMock, getCommentsMock } from '../comment/index.mock'; -import { getCreateCommentsArrayMock } from '../create_comment/index.mock'; -import { - importComment, - ImportCommentsArray, - importCommentsArray, - ImportCommentsArrayOrUndefined, - importCommentsArrayOrUndefined, -} from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('ImportComment', () => { - describe('importComment', () => { - test('it passes validation with a typical comment', () => { - const payload = getCommentsMock(); - const decoded = importComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it passes validation with a new comment', () => { - const payload = { comment: 'new comment' }; - const decoded = importComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it fails validation when undefined', () => { - const payload = undefined; - const decoded = importComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "(({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>) | {| comment: NonEmptyString |})"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('importCommentsArray', () => { - test('it passes validation an array of Comment', () => { - const payload = getCommentsArrayMock(); - const decoded = importCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it passes validation an array of CreateComment', () => { - const payload = getCreateCommentsArrayMock(); - const decoded = importCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it passes validation an array of Comment and CreateComment', () => { - const payload = [...getCommentsArrayMock(), ...getCreateCommentsArrayMock()]; - const decoded = importCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it fails validation when undefined', () => { - const payload = undefined; - const decoded = importCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "Array<(({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>) | {| comment: NonEmptyString |})>"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it fails validation when array includes non ImportComment types', () => { - const payload = [1] as unknown as ImportCommentsArray; - const decoded = importCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<(({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>) | {| comment: NonEmptyString |})>"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('importCommentsArrayOrUndefined', () => { - test('it passes validation an array of ImportComment', () => { - const payload = [...getCommentsArrayMock(), ...getCreateCommentsArrayMock()]; - const decoded = importCommentsArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it passes validation when undefined', () => { - const payload = undefined; - const decoded = importCommentsArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it fails validation when array includes non ImportComment types', () => { - const payload = [1] as unknown as ImportCommentsArrayOrUndefined; - const decoded = importCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<(({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>) | {| comment: NonEmptyString |})>"', - ]); - expect(message.schema).toEqual({}); - }); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.ts deleted file mode 100644 index 4511b28078bc6..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { createComment } from '../create_comment'; -import { comment } from '../comment'; - -export const importComment = t.union([comment, createComment]); - -export type ImportComment = t.TypeOf; -export const importCommentsArray = t.array(importComment); -export type ImportCommentsArray = t.TypeOf; -export const importCommentsArrayOrUndefined = t.union([importCommentsArray, t.undefined]); -export type ImportCommentsArrayOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/include_expired_exceptions/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/include_expired_exceptions/index.ts deleted file mode 100644 index 7c40e74d81895..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/include_expired_exceptions/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const include_expired_exceptions = t.keyof({ true: null, false: null }); -export const includeExpiredExceptionsOrUndefined = t.union([ - include_expired_exceptions, - t.undefined, -]); -export type IncludeExpiredExceptionsOrUndefined = t.TypeOf< - typeof includeExpiredExceptionsOrUndefined ->; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/index.ts deleted file mode 100644 index b30ac02dab962..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './comment'; -export * from './create_comment'; -export * from './created_at'; -export * from './created_by'; -export * from './cursor'; -export * from './default_namespace'; -export * from './default_namespace_array'; -export * from './default_create_comments_array'; -export * from './default_import_comments_array'; -export * from './description'; -export * from './deserializer'; -export * from './endpoint'; -export * from './entries'; -export * from './entries_exist'; -export * from './entries_list'; -export * from './entry_match'; -export * from './entry_match_any'; -export * from './entry_match_wildcard'; -export * from './entry_nested'; -export * from './exception_export_details'; -export * from './exception_list'; -export * from './exception_list_item_type'; -export * from './expire_time'; -export * from './filter'; -export * from './id'; -export * from './immutable'; -export * from './import_comment'; -export * from './item_id'; -export * from './list_id'; -export * from './list_operator'; -export * from './list_type'; -export * from './lists'; -export * from './lists_default_array'; -export * from './max_size'; -export * from './meta'; -export * from './name'; -export * from './namespace_type'; -export * from './non_empty_entries_array'; -export * from './non_empty_nested_entries_array'; -export * from './os_type'; -export * from './page'; -export * from './per_page'; -export * from './pit'; -export * from './search'; -export * from './search_after'; -export * from './serializer'; -export * from './sort_field'; -export * from './sort_order'; -export * from './tags'; -export * from './tie_breaker_id'; -export * from './timestamp'; -export * from './total'; -export * from './type'; -export * from './underscore_version'; -export * from './update_comment'; -export * from './updated_at'; -export * from './updated_by'; -export * from './refresh'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/item/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/item/index.ts deleted file mode 100644 index d69ec53584001..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/item/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const item = t.string; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/item_id/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/item_id/index.ts deleted file mode 100644 index 0e4551ad5c8f6..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/item_id/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; - -export const item_id = NonEmptyString; -export type ItemId = t.TypeOf; -export const itemIdOrUndefined = t.union([item_id, t.undefined]); -export type ItemIdOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/list_id/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/list_id/index.ts deleted file mode 100644 index 88e88aa8bc3c7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/list_id/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; - -export const list_id = NonEmptyString; -export type ListId = t.TypeOf; -export const list_idOrUndefined = t.union([list_id, t.undefined]); -export type ListIdOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.test.ts deleted file mode 100644 index 054af26b4a620..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { ListOperatorEnum as OperatorEnum, listOperator as operator } from '.'; - -describe('operator', () => { - test('it should validate for "included"', () => { - const payload = 'included'; - const decoded = operator.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate for "excluded"', () => { - const payload = 'excluded'; - const decoded = operator.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should contain same amount of keys as enum', () => { - // Might seem like a weird test, but its meant to - // ensure that if operator is updated, you - // also update the operatorEnum, a workaround - // for io-ts not yet supporting enums - // https://github.com/gcanti/io-ts/issues/67 - const keys = Object.keys(operator.keys).sort().join(',').toLowerCase(); - const enumKeys = Object.keys(OperatorEnum).sort().join(',').toLowerCase(); - - expect(keys).toEqual(enumKeys); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.ts deleted file mode 100644 index 574a64e0f0320..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const listOperator = t.keyof({ excluded: null, included: null }); -export type ListOperator = t.TypeOf; -export enum ListOperatorEnum { - INCLUDED = 'included', - EXCLUDED = 'excluded', -} - -export const listOperatorType = t.keyof({ - nested: null, - match: null, - match_any: null, - wildcard: null, - exists: null, - list: null, -}); -export type ListOperatorType = t.TypeOf; -export enum ListOperatorTypeEnum { - NESTED = 'nested', - MATCH = 'match', - MATCH_ANY = 'match_any', - WILDCARD = 'wildcard', - EXISTS = 'exists', - LIST = 'list', -} diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/list_type/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/list_type/index.ts deleted file mode 100644 index 716d9a6b24d7e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/list_type/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const list_type = t.keyof({ item: null, list: null }); -export type ListType = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts deleted file mode 100644 index c8319867b5775..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { List, ListArray } from '.'; -import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; - -export const getListMock = (): List => ({ - id: 'some_uuid', - list_id: 'list_id_single', - namespace_type: 'single', - type: 'detection', -}); - -export const getEndpointListMock = (): List => ({ - id: ENDPOINT_LIST_ID, - list_id: ENDPOINT_LIST_ID, - namespace_type: 'agnostic', - type: 'endpoint', -}); - -export const getListArrayMock = (): ListArray => [getListMock(), getEndpointListMock()]; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.test.ts deleted file mode 100644 index 57c221f10384f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getEndpointListMock, getListArrayMock, getListMock } from './index.mock'; -import { List, list, ListArray, listArray, ListArrayOrUndefined, listArrayOrUndefined } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('Lists', () => { - describe('list', () => { - test('it should validate a list', () => { - const payload = getListMock(); - const decoded = list.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate a list with "namespace_type" of "agnostic"', () => { - const payload = getEndpointListMock(); - const decoded = list.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT validate a list without an "id"', () => { - const payload = getListMock(); - // @ts-expect-error - delete payload.id; - const decoded = list.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT validate a list without "namespace_type"', () => { - const payload = getListMock(); - // @ts-expect-error - delete payload.namespace_type; - const decoded = list.decode(payload); - const message = pipe(decoded, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "namespace_type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra keys', () => { - const payload: List & { - extraKey?: string; - } = getListMock(); - payload.extraKey = 'some value'; - const decoded = list.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getListMock()); - }); - }); - - describe('listArray', () => { - test('it should validate an array of lists', () => { - const payload = getListArrayMock(); - const decoded = listArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate when unexpected type found in array', () => { - const payload = [1] as unknown as ListArray; - const decoded = listArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<{| id: NonEmptyString, list_id: NonEmptyString, type: "detection" | "rule_default" | "endpoint" | "endpoint_trusted_apps" | "endpoint_events" | "endpoint_host_isolation_exceptions" | "endpoint_blocklists", namespace_type: "agnostic" | "single" |}>"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('listArrayOrUndefined', () => { - test('it should validate an array of lists', () => { - const payload = getListArrayMock(); - const decoded = listArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate when undefined', () => { - const payload = undefined; - const decoded = listArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an item that is not of type "list" in array', () => { - const payload = [1] as unknown as ListArrayOrUndefined; - const decoded = listArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "(Array<{| id: NonEmptyString, list_id: NonEmptyString, type: "detection" | "rule_default" | "endpoint" | "endpoint_trusted_apps" | "endpoint_events" | "endpoint_host_isolation_exceptions" | "endpoint_blocklists", namespace_type: "agnostic" | "single" |}> | undefined)"', - 'Invalid value "[1]" supplied to "(Array<{| id: NonEmptyString, list_id: NonEmptyString, type: "detection" | "rule_default" | "endpoint" | "endpoint_trusted_apps" | "endpoint_events" | "endpoint_host_isolation_exceptions" | "endpoint_blocklists", namespace_type: "agnostic" | "single" |}> | undefined)"', - ]); - expect(message.schema).toEqual({}); - }); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.ts deleted file mode 100644 index 564ce7833b0f0..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -import { exceptionListType } from '../exception_list'; -import { namespaceType } from '../default_namespace'; - -export const list = t.exact( - t.type({ - id: NonEmptyString, - list_id: NonEmptyString, - type: exceptionListType, - namespace_type: namespaceType, - }) -); - -export type List = t.TypeOf; -export const listArray = t.array(list); -export type ListArray = t.TypeOf; -export const listArrayOrUndefined = t.union([listArray, t.undefined]); -export type ListArrayOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.test.ts deleted file mode 100644 index fa4f22c4718e1..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultListArray } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getListArrayMock } from '../lists/index.mock'; - -describe('lists_default_array', () => { - test('it should return a default array when null', () => { - const payload = null; - const decoded = DefaultListArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([]); - }); - - test('it should return a default array when undefined', () => { - const payload = undefined; - const decoded = DefaultListArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([]); - }); - - test('it should validate an empty array', () => { - const payload: string[] = []; - const decoded = DefaultListArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of lists', () => { - const payload = getListArrayMock(); - const decoded = DefaultListArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate an array of non accepted types', () => { - // Terrible casting for purpose of tests - const payload = [1] as unknown; - const decoded = DefaultListArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "DefaultListArray"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.ts deleted file mode 100644 index a014d769410ee..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { list, ListArray } from '../lists'; - -/** - * Types the DefaultListArray as: - * - If null or undefined, then a default array of type list will be set - */ -export const DefaultListArray = new t.Type( - 'DefaultListArray', - t.array(list).is, - (input, context): Either => - input == null ? t.success([]) : t.array(list).validate(input, context), - t.identity -); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.test.ts deleted file mode 100644 index 9ddf86818eaf7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { exactCheck } from '@kbn/securitysolution-io-ts-utils'; -import { maxSizeOrUndefined } from '.'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; - -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('maxSizeOrUndefined', () => { - test('it will validate a correct max value', () => { - const payload = 123; - const decoded = maxSizeOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will fail to validate a 0', () => { - const payload = 0; - const decoded = maxSizeOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "(PositiveIntegerGreaterThanZero | undefined)"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it will fail to validate a -1', () => { - const payload = -1; - const decoded = maxSizeOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "(PositiveIntegerGreaterThanZero | undefined)"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it will fail to validate a string', () => { - const payload = '123'; - const decoded = maxSizeOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "123" supplied to "(PositiveIntegerGreaterThanZero | undefined)"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.ts deleted file mode 100644 index 0c99edf692527..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import { PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; -import * as t from 'io-ts'; - -export const max_size = PositiveIntegerGreaterThanZero; -export type MaxSize = t.TypeOf; - -export const maxSizeOrUndefined = t.union([max_size, t.undefined]); -export type MaxSizeOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/meta/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/meta/index.ts deleted file mode 100644 index 07f329819fc12..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/meta/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const meta = t.object; -export type Meta = t.TypeOf; -export const metaOrUndefined = t.union([meta, t.undefined]); -export type MetaOrUndefined = t.TypeOf; - -export const nullableMetaOrUndefined = t.union([metaOrUndefined, t.null]); -export type NullableMetaOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/name/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/name/index.ts deleted file mode 100644 index 5d4a13c06ceef..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/name/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const name = t.string; -export type Name = t.TypeOf; -export const nameOrUndefined = t.union([name, t.undefined]); -export type NameOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/namespace_type/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/namespace_type/index.ts deleted file mode 100644 index b8d052910b86a..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/namespace_type/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import { DefaultNamespace } from '../default_namespace'; - -export const namespace_type = DefaultNamespace; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.test.ts deleted file mode 100644 index 1128dd53871ee..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.test.ts +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { EntriesArray } from '../entries'; -import { nonEmptyEntriesArray } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getEntryMatchMock } from '../entry_match/index.mock'; -import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; -import { getEntryExistsMock } from '../entries_exist/index.mock'; -import { - getEntriesArrayMock, - getListAndNonListEntriesArrayMock, - getListEntriesArrayMock, -} from '../entries/index.mock'; -import { getEntryNestedMock } from '../entry_nested/index.mock'; - -describe('non_empty_entries_array', () => { - test('it should FAIL validation when given an empty array', () => { - const payload: EntriesArray = []; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "[]" supplied to "NonEmptyEntriesArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when given "undefined"', () => { - const payload = undefined; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "NonEmptyEntriesArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when given "null"', () => { - const payload = null; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "null" supplied to "NonEmptyEntriesArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should validate an array of "match" entries', () => { - const payload: EntriesArray = [getEntryMatchMock(), getEntryMatchMock()]; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of "match_any" entries', () => { - const payload: EntriesArray = [getEntryMatchAnyMock(), getEntryMatchAnyMock()]; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of "exists" entries', () => { - const payload: EntriesArray = [getEntryExistsMock(), getEntryExistsMock()]; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of "list" entries', () => { - const payload: EntriesArray = [...getListEntriesArrayMock()]; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of "nested" entries', () => { - const payload: EntriesArray = [getEntryNestedMock(), getEntryNestedMock()]; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of entries', () => { - const payload: EntriesArray = [...getEntriesArrayMock()]; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when given an array of entries of value list and non-value list entries', () => { - const payload: EntriesArray = [...getListAndNonListEntriesArrayMock()]; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Cannot have entry of type list and other']); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when given an array of non entries', () => { - const payload = [1]; - const decoded = nonEmptyEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "NonEmptyEntriesArray"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.ts deleted file mode 100644 index a5e06d5bb2c43..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { entriesArray, EntriesArray } from '../entries'; -import { entriesList } from '../entries_list'; - -/** - * Types the nonEmptyEntriesArray as: - * - An array of entries of length 1 or greater - * - */ -export const nonEmptyEntriesArray = new t.Type( - 'NonEmptyEntriesArray', - entriesArray.is, - (input, context): Either => { - if (Array.isArray(input) && input.length === 0) { - return t.failure(input, context); - } else { - if ( - Array.isArray(input) && - input.some((entry) => entriesList.is(entry)) && - input.some((entry) => !entriesList.is(entry)) - ) { - // fail when an exception item contains both a value list entry and a non-value list entry - return t.failure(input, context, 'Cannot have entry of type list and other'); - } - return entriesArray.validate(input, context); - } - }, - t.identity -); - -export type NonEmptyEntriesArray = t.OutputOf; -export type NonEmptyEntriesArrayDecoded = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.test.ts deleted file mode 100644 index afb62d1f87685..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { EntriesArray } from '../entries'; -import { nonEmptyNestedEntriesArray } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getEntryMatchMock } from '../entry_match/index.mock'; -import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; -import { getEntryExistsMock } from '../entries_exist/index.mock'; -import { getEntryNestedMock } from '../entry_nested/index.mock'; - -describe('non_empty_nested_entries_array', () => { - test('it should FAIL validation when given an empty array', () => { - const payload: EntriesArray = []; - const decoded = nonEmptyNestedEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "[]" supplied to "NonEmptyNestedEntriesArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when given "undefined"', () => { - const payload = undefined; - const decoded = nonEmptyNestedEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "NonEmptyNestedEntriesArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should FAIL validation when given "null"', () => { - const payload = null; - const decoded = nonEmptyNestedEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "null" supplied to "NonEmptyNestedEntriesArray"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should validate an array of "match" entries', () => { - const payload: EntriesArray = [getEntryMatchMock(), getEntryMatchMock()]; - const decoded = nonEmptyNestedEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of "match_any" entries', () => { - const payload: EntriesArray = [getEntryMatchAnyMock(), getEntryMatchAnyMock()]; - const decoded = nonEmptyNestedEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate an array of "exists" entries', () => { - const payload: EntriesArray = [getEntryExistsMock(), getEntryExistsMock()]; - const decoded = nonEmptyNestedEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when given an array of "nested" entries', () => { - const payload: EntriesArray = [getEntryNestedMock(), getEntryNestedMock()]; - const decoded = nonEmptyNestedEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "operator"', - 'Invalid value "nested" supplied to "type"', - 'Invalid value "undefined" supplied to "value"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should validate an array of entries', () => { - const payload: EntriesArray = [ - getEntryExistsMock(), - getEntryMatchAnyMock(), - getEntryMatchMock(), - ]; - const decoded = nonEmptyNestedEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should FAIL validation when given an array of non entries', () => { - const payload = [1]; - const decoded = nonEmptyNestedEntriesArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "NonEmptyNestedEntriesArray"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.ts deleted file mode 100644 index 73a00e75010f3..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { Either } from 'fp-ts/lib/Either'; -import { entriesMatch } from '../entry_match'; -import { entriesMatchAny } from '../entry_match_any'; -import { entriesExists } from '../entries_exist'; - -export const nestedEntryItem = t.union([entriesMatch, entriesMatchAny, entriesExists]); -export const nestedEntriesArray = t.array(nestedEntryItem); -export type NestedEntriesArray = t.TypeOf; - -/** - * Types the nonEmptyNestedEntriesArray as: - * - An array of entries of length 1 or greater - * - */ -export const nonEmptyNestedEntriesArray = new t.Type< - NestedEntriesArray, - NestedEntriesArray, - unknown ->( - 'NonEmptyNestedEntriesArray', - nestedEntriesArray.is, - (input, context): Either => { - if (Array.isArray(input) && input.length === 0) { - return t.failure(input, context); - } else { - return nestedEntriesArray.validate(input, context); - } - }, - t.identity -); - -export type NonEmptyNestedEntriesArray = t.OutputOf; -export type NonEmptyNestedEntriesArrayDecoded = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.test.ts deleted file mode 100644 index 566a2aa0973aa..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { exactCheck } from '@kbn/securitysolution-io-ts-utils'; -import { osType, osTypeArrayOrUndefined } from '.'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; - -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('osType', () => { - test('it will validate a correct osType', () => { - const payload = 'windows'; - const decoded = osType.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will fail to validate an incorrect osType', () => { - const payload = 'foo'; - const decoded = osType.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "foo" supplied to ""linux" | "macos" | "windows""', - ]); - expect(message.schema).toEqual({}); - }); - - test('it will default to an empty array when osTypeArrayOrUndefined is used', () => { - const payload = undefined; - const decoded = osTypeArrayOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([]); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.ts deleted file mode 100644 index 1dfbb9687e214..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { DefaultArray } from '@kbn/securitysolution-io-ts-types'; - -export const osType = t.keyof({ - linux: null, - macos: null, - windows: null, -}); -export type OsType = t.TypeOf; - -export const osTypeArray = DefaultArray(osType); -export type OsTypeArray = t.TypeOf; - -export const osTypeArrayOrUndefined = t.union([osTypeArray, t.undefined]); -export type OsTypeArrayOrUndefined = t.OutputOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/page/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/page/index.ts deleted file mode 100644 index 58c5581cc6e26..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/page/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const page = t.number; // TODO: Change this out for PositiveNumber from siem -export type Page = t.TypeOf; - -export const pageOrUndefined = t.union([page, t.undefined]); -export type PageOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/per_page/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/per_page/index.ts deleted file mode 100644 index 9ab3d1dde38c9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/per_page/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const per_page = t.number; // TODO: Change this out for PositiveNumber from siem -export type PerPage = t.TypeOf; - -export const perPageOrUndefined = t.union([per_page, t.undefined]); -export type PerPageOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.test.ts deleted file mode 100644 index 36bc95ce17862..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { exactCheck } from '@kbn/securitysolution-io-ts-utils'; -import { pitOrUndefined } from '.'; - -import * as t from 'io-ts'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; - -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('pitOrUndefined', () => { - test('it will validate a correct pit', () => { - const payload = { id: '123', keepAlive: '1m' }; - const decoded = pitOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will validate with the value of "undefined"', () => { - const obj = t.exact( - t.type({ - pit_id: pitOrUndefined, - }) - ); - const payload: t.TypeOf = { - pit_id: undefined, - }; - const decoded = obj.decode({ - pit_id: undefined, - }); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will validate a correct pit without having a "keepAlive"', () => { - const payload = { id: '123' }; - const decoded = pitOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will fail to validate an incorrect pit', () => { - const payload = 'foo'; - const decoded = pitOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "foo" supplied to "({| id: string, keepAlive: (string | undefined) |} | undefined)"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.ts deleted file mode 100644 index 3347f986113e2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const pitId = t.string; -export const pit = t.exact( - t.type({ - id: pitId, - keepAlive: t.union([t.string, t.undefined]), - }) -); -export const pitOrUndefined = t.union([pit, t.undefined]); - -export type Pit = t.TypeOf; -export type PitId = t.TypeOf; -export type PitOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/refresh/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/refresh/index.ts deleted file mode 100644 index faa301fd450ae..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/refresh/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const refresh = t.union([t.literal('true'), t.literal('false')]); -export const refreshWithWaitFor = t.union([ - t.literal('true'), - t.literal('false'), - t.literal('wait_for'), -]); -export type Refresh = t.TypeOf; -export type RefreshWithWaitFor = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/required_keep_undefined/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/required_keep_undefined/index.ts deleted file mode 100644 index 5e6b30cf720cb..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/required_keep_undefined/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/** - * This makes any optional property the same as Required would but also has the - * added benefit of keeping your undefined. - * - * For example: - * type A = RequiredKeepUndefined<{ a?: undefined; b: number }>; - * - * will yield a type of: - * type A = { a: undefined; b: number; } - * @deprecated This has no replacement. We should stop using/relying on this and just remove it. - */ -export type RequiredKeepUndefined = { [K in keyof T]-?: [T[K]] } extends infer U - ? U extends Record - ? { [K in keyof U]: U[K][0] } - : never - : never; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.test.ts deleted file mode 100644 index 1224b277c8520..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { exactCheck } from '@kbn/securitysolution-io-ts-utils'; -import { searchOrUndefined } from '.'; - -import * as t from 'io-ts'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; - -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('search', () => { - test('it will validate a correct search', () => { - const payload = 'name:foo'; - const decoded = searchOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will validate with the value of "undefined"', () => { - const obj = t.exact( - t.type({ - search: searchOrUndefined, - }) - ); - const payload: t.TypeOf = { - search: undefined, - }; - const decoded = obj.decode({ - pit_id: undefined, - }); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will fail to validate an incorrect search', () => { - const payload = ['foo']; - const decoded = searchOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "["foo"]" supplied to "(string | undefined)"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.ts deleted file mode 100644 index 85e360b842672..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const search = t.string; -export type Search = t.TypeOf; - -export const searchOrUndefined = t.union([search, t.undefined]); -export type SearchOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.test.ts deleted file mode 100644 index d06198272792a..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { exactCheck } from '@kbn/securitysolution-io-ts-utils'; -import { searchAfterOrUndefined } from '.'; - -import * as t from 'io-ts'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; - -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('searchAfter', () => { - test('it will validate a correct search_after', () => { - const payload = ['test-1', 'test-2']; - const decoded = searchAfterOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will validate with the value of "undefined"', () => { - const obj = t.exact( - t.type({ - search_after: searchAfterOrUndefined, - }) - ); - const payload: t.TypeOf = { - search_after: undefined, - }; - const decoded = obj.decode({ - pit_id: undefined, - }); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will fail to validate an incorrect search_after', () => { - const payload = 'foo'; - const decoded = searchAfterOrUndefined.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "foo" supplied to "(Array | undefined)"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.ts deleted file mode 100644 index 5cef26cbb0c47..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const search_after = t.array(t.string); -export type SearchAfter = t.TypeOf; - -export const searchAfterOrUndefined = t.union([search_after, t.undefined]); -export type SearchAfterOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/serializer/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/serializer/index.ts deleted file mode 100644 index 7eb585c068e2d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/serializer/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const serializer = t.string; -export type Serializer = t.TypeOf; -export const serializerOrUndefined = t.union([serializer, t.undefined]); -export type SerializerOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_field/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_field/index.ts deleted file mode 100644 index e2c61659a94e4..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_field/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const sort_field = t.string; -export const sortFieldOrUndefined = t.union([sort_field, t.undefined]); -export type SortFieldOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_order/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_order/index.ts deleted file mode 100644 index fb075ff63fee4..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_order/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const sort_order = t.keyof({ asc: null, desc: null }); -export const sortOrderOrUndefined = t.union([sort_order, t.undefined]); -export type SortOrderOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/tags/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/tags/index.ts deleted file mode 100644 index ad99a1d0800fb..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/tags/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { DefaultStringArray } from '@kbn/securitysolution-io-ts-types'; - -export const tags = DefaultStringArray; -export type Tags = t.TypeOf; -export const tagsOrUndefined = t.union([tags, t.undefined]); -export type TagsOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/tie_breaker_id/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/tie_breaker_id/index.ts deleted file mode 100644 index 0e393c7f154b8..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/tie_breaker_id/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const tie_breaker_id = t.string; // TODO: Use UUID for this instead of a string for validation diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/timestamp/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/timestamp/index.ts deleted file mode 100644 index ba47dd545fbbb..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/timestamp/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { IsoDateString } from '@kbn/securitysolution-io-ts-types'; - -export const timestamp = IsoDateString; -export const timestampOrUndefined = t.union([IsoDateString, t.undefined]); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/total/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/total/index.ts deleted file mode 100644 index f3c84417cd419..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/total/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const total = t.number; // TODO: Change this out for PositiveNumber from siem -export const totalUndefined = t.union([total, t.undefined]); -export type TotalOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.test.ts deleted file mode 100644 index 60156cda9fe6d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { Type, type } from '.'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('type', () => { - test('it will work with a given expected type', () => { - const payload: Type = 'keyword'; - const decoded = type.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it will give an error if given a type that does not exist', () => { - const payload: Type | 'madeup' = 'madeup'; - const decoded = type.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "madeup" supplied to ""binary" | "boolean" | "byte" | "date" | "date_nanos" | "date_range" | "double" | "double_range" | "float" | "float_range" | "geo_point" | "geo_shape" | "half_float" | "integer" | "integer_range" | "ip" | "ip_range" | "keyword" | "long" | "long_range" | "shape" | "short" | "text""', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.ts deleted file mode 100644 index d617fd2cccdf3..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -/** - * Types of all the regular single value list items but not exception list - * or exception list types. Those types are in the list_types folder. - */ -export const type = t.keyof({ - binary: null, - boolean: null, - byte: null, - date: null, - date_nanos: null, - date_range: null, - double: null, - double_range: null, - float: null, - float_range: null, - geo_point: null, - geo_shape: null, - half_float: null, - integer: null, - integer_range: null, - ip: null, - ip_range: null, - keyword: null, - long: null, - long_range: null, - shape: null, - short: null, - text: null, -}); - -export const typeOrUndefined = t.union([type, t.undefined]); -export type Type = t.TypeOf; -export type TypeOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/underscore_version/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/underscore_version/index.ts deleted file mode 100644 index 2e4901990fb5f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/underscore_version/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const _version = t.string; -export const _versionOrUndefined = t.union([_version, t.undefined]); -export type _VersionOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.mock.ts deleted file mode 100644 index c84db08f8c93c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.mock.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { UpdateComment, UpdateCommentsArray } from '.'; -import { ID } from '../../constants/index.mock'; - -export const getUpdateCommentMock = (): UpdateComment => ({ - comment: 'some comment', - id: ID, -}); - -export const getUpdateCommentsArrayMock = (): UpdateCommentsArray => [ - getUpdateCommentMock(), - getUpdateCommentMock(), -]; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.test.ts deleted file mode 100644 index 88cdfbdd573e6..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.test.ts +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { getUpdateCommentMock, getUpdateCommentsArrayMock } from './index.mock'; -import { - UpdateComment, - updateComment, - UpdateCommentsArray, - updateCommentsArray, - UpdateCommentsArrayOrUndefined, - updateCommentsArrayOrUndefined, -} from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('UpdateComment', () => { - describe('updateComment', () => { - test('it should pass validation when supplied typical comment update', () => { - const payload = getUpdateCommentMock(); - const decoded = updateComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when supplied an undefined for "comment"', () => { - const payload = getUpdateCommentMock(); - // @ts-expect-error - delete payload.comment; - const decoded = updateComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "comment"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an empty string for "comment"', () => { - const payload = { ...getUpdateCommentMock(), comment: '' }; - const decoded = updateComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "comment"']); - expect(message.schema).toEqual({}); - }); - - test('it should pass validation when supplied an undefined for "id"', () => { - const payload = getUpdateCommentMock(); - delete payload.id; - const decoded = updateComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when supplied an empty string for "id"', () => { - const payload = { ...getUpdateCommentMock(), id: '' }; - const decoded = updateComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should strip out extra key passed in', () => { - const payload: UpdateComment & { - extraKey?: string; - } = { ...getUpdateCommentMock(), extraKey: 'some new value' }; - const decoded = updateComment.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getUpdateCommentMock()); - }); - }); - - describe('updateCommentsArray', () => { - test('it should pass validation when supplied an array of comments', () => { - const payload = getUpdateCommentsArrayMock(); - const decoded = updateCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when undefined', () => { - const payload = undefined; - const decoded = updateCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "Array<({| comment: NonEmptyString |} & Partial<{| id: NonEmptyString |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when array includes non comments types', () => { - const payload = [1] as unknown as UpdateCommentsArray; - const decoded = updateCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString |} & Partial<{| id: NonEmptyString |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('updateCommentsArrayOrUndefined', () => { - test('it should pass validation when supplied an array of comments', () => { - const payload = getUpdateCommentsArrayMock(); - const decoded = updateCommentsArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should pass validation when supplied when undefined', () => { - const payload = undefined; - const decoded = updateCommentsArrayOrUndefined.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when array includes non comments types', () => { - const payload = [1] as unknown as UpdateCommentsArrayOrUndefined; - const decoded = updateCommentsArray.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString |} & Partial<{| id: NonEmptyString |}>)>"', - ]); - expect(message.schema).toEqual({}); - }); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.ts deleted file mode 100644 index 79a721c8dad54..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -import { id } from '../id'; - -export const updateComment = t.intersection([ - t.exact( - t.type({ - comment: NonEmptyString, - }) - ), - t.exact( - t.partial({ - id, - }) - ), -]); - -export type UpdateComment = t.TypeOf; -export const updateCommentsArray = t.array(updateComment); -export type UpdateCommentsArray = t.TypeOf; -export const updateCommentsArrayOrUndefined = t.union([updateCommentsArray, t.undefined]); -export type UpdateCommentsArrayOrUndefined = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_at/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_at/index.ts deleted file mode 100644 index a6c0a803e6dbc..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_at/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const updated_at = t.string; // TODO: Make this into an ISO Date string check diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_by/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_by/index.ts deleted file mode 100644 index b99396254c914..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_by/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import * as t from 'io-ts'; - -export const updated_by = t.string; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/value/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/value/index.ts deleted file mode 100644 index cad092aee4b79..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/value/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const value = t.string; -export const valueOrUndefined = t.union([value, t.undefined]); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/constants/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/constants/index.mock.ts deleted file mode 100644 index 4d09fc1efbeb3..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/constants/index.mock.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EndpointEntriesArray } from '../common/endpoint/entries'; -import { EntriesArray, Entry } from '../common/entries'; -import { EntryMatch } from '../common/entry_match'; -import { EntryNested } from '../common/entry_nested'; -import { OsTypeArray } from '../common/os_type'; - -export const DATE_NOW = '2020-04-20T15:25:31.830Z'; -export const OLD_DATE_RELATIVE_TO_DATE_NOW = '2020-04-19T15:25:31.830Z'; -export const USER = 'some user'; -export const ELASTIC_USER = 'elastic'; -export const LIST_INDEX = '.lists'; -export const LIST_ITEM_INDEX = '.items'; -export const NAME = 'some name'; -export const DESCRIPTION = 'some description'; -export const LIST_ID = 'some-list-id'; -export const LIST_ITEM_ID = 'some-list-item-id'; -export const TIE_BREAKER = '6a76b69d-80df-4ab2-8c3e-85f466b06a0e'; -export const TIE_BREAKERS = [ - '21530991-4051-46ec-bc35-2afa09a1b0b5', - '3c662054-ae37-4aa9-9936-3e8e2ea26775', - '60e49a20-3a23-48b6-8bf9-ed5e3b70f7a0', - '38814080-a40f-4358-992a-3b875f9b7dec', - '29fa61be-aaaf-411c-a78a-7059e3f723f1', - '9c19c959-cb9d-4cd2-99e4-1ea2baf0ef0e', - 'd409308c-f94b-4b3a-8234-bbd7a80c9140', - '87824c99-cd83-45c4-8aa6-4ad95dfea62c', - '7b940c17-9355-479f-b882-f3e575718f79', - '5983ad0c-4ef4-4fa0-8308-80ab9ecc4f74', -]; -export const META = {}; -export const TYPE = 'ip'; -export const VALUE = '127.0.0.1'; -export const VALUE_2 = '255.255.255'; -export const NAMESPACE_TYPE = 'single'; -export const NESTED_FIELD = 'parent.field'; - -// Exception List specific -export const ID = 'uuid_here'; -export const ITEM_ID = 'some-list-item-id'; -export const DETECTION_TYPE = 'detection'; -export const ENDPOINT_TYPE = 'endpoint'; -export const FIELD = 'host.name'; -export const OPERATOR = 'included'; -export const OPERATOR_EXCLUDED = 'excluded'; -export const ENTRY_VALUE = 'some host name'; -export const MATCH = 'match'; -export const MATCH_ANY = 'match_any'; -export const WILDCARD = 'wildcard'; -export const MAX_IMPORT_PAYLOAD_BYTES = 9000000; -export const IMPORT_BUFFER_SIZE = 1000; -export const LIST = 'list'; -export const EXISTS = 'exists'; -export const NESTED = 'nested'; -export const ENTRIES: EntriesArray = [ - { - entries: [{ field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }], - field: 'some.parentField', - type: 'nested', - }, - { field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' }, -]; -export const ENDPOINT_ENTRIES: EndpointEntriesArray = [ - { - entries: [{ field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }], - field: 'some.parentField', - type: 'nested', - }, - { field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' }, -]; -// ENTRIES_WITH_IDS should only be used to mock out functionality of a collection of transforms -// that are UI specific and useful for UI concerns that are inserted between the -// API and the actual user interface. In some ways these might be viewed as -// technical debt or to compensate for the differences and preferences -// of how ReactJS might prefer data vs. how we want to model data. -export const ENTRIES_WITH_IDS: EntriesArray = [ - { - entries: [ - { - field: 'nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as EntryMatch & { id: string }, - ], - field: 'some.parentField', - id: '123', - type: 'nested', - } as EntryNested & { id: string }, - { - field: 'some.not.nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as Entry & { id: string }, -]; -export const ITEM_TYPE = 'simple'; -export const OS_TYPES: OsTypeArray = ['windows']; -export const TAGS = []; -export const COMMENTS = []; -export const FILTER = 'name:Nicolas Bourbaki'; -export const CURSOR = 'c29tZXN0cmluZ2ZvcnlvdQ=='; -export const _VERSION = 'WzI5NywxXQ=='; -export const VERSION = 1; -export const IMMUTABLE = false; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.mock.ts deleted file mode 100644 index db83807b0271d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.mock.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { CreateEndpointListItemSchema } from '.'; -import { - COMMENTS, - DESCRIPTION, - ENDPOINT_ENTRIES, - ITEM_TYPE, - META, - NAME, - OS_TYPES, - TAGS, -} from '../../constants/index.mock'; - -export const getCreateEndpointListItemSchemaMock = (): CreateEndpointListItemSchema => ({ - comments: COMMENTS, - description: DESCRIPTION, - entries: ENDPOINT_ENTRIES, - item_id: undefined, - meta: META, - name: NAME, - os_types: OS_TYPES, - tags: TAGS, - type: ITEM_TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.test.ts deleted file mode 100644 index 9dc599a75ad5c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.test.ts +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { getCreateEndpointListItemSchemaMock } from './index.mock'; -import { CreateEndpointListItemSchema, createEndpointListItemSchema } from '.'; -import { getCreateCommentsArrayMock } from '../../common/create_comment/index.mock'; -import { getCommentsMock } from '../../common/comment/index.mock'; -import { CommentsArray } from '../../common/comment'; - -describe('create_endpoint_list_item_schema', () => { - test('it should pass validation when supplied a typical list item request not counting the auto generated uuid', () => { - const payload = getCreateEndpointListItemSchemaMock(); - const decoded = createEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateEndpointListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when supplied an undefined for "description"', () => { - const payload = getCreateEndpointListItemSchemaMock(); - // @ts-expect-error - delete payload.description; - const decoded = createEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an undefined for "name"', () => { - const payload = getCreateEndpointListItemSchemaMock(); - // @ts-expect-error - delete payload.name; - const decoded = createEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an undefined for "type"', () => { - const payload = getCreateEndpointListItemSchemaMock(); - // @ts-expect-error - delete payload.type; - const decoded = createEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied a "list_id" since it does not required one', () => { - const inputPayload: CreateEndpointListItemSchema & { list_id: string } = { - ...getCreateEndpointListItemSchemaMock(), - list_id: 'list-123', - }; - const decoded = createEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "list_id"']); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied a "namespace_type" since it does not required one', () => { - const inputPayload: CreateEndpointListItemSchema & { namespace_type: string } = { - ...getCreateEndpointListItemSchemaMock(), - namespace_type: 'single', - }; - const decoded = createEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "namespace_type"']); - expect(message.schema).toEqual({}); - }); - - test('it should pass validation when supplied an undefined for "meta" but strip it out and generate a correct body not counting the auto generated uuid', () => { - const payload = getCreateEndpointListItemSchemaMock(); - const outputPayload = getCreateEndpointListItemSchemaMock(); - delete payload.meta; - delete outputPayload.meta; - const decoded = createEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateEndpointListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should pass validation when supplied an undefined for "comments" but return an array and generate a correct body not counting the auto generated uuid', () => { - const inputPayload = getCreateEndpointListItemSchemaMock(); - const outputPayload = getCreateEndpointListItemSchemaMock(); - delete inputPayload.comments; - outputPayload.comments = []; - const decoded = createEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateEndpointListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should pass validation when supplied "comments" array', () => { - const inputPayload = { - ...getCreateEndpointListItemSchemaMock(), - comments: getCreateCommentsArrayMock(), - }; - const decoded = createEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateEndpointListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(inputPayload); - }); - - test('it should fail validation when supplied "comments" with "created_at", "created_by", or "id" values', () => { - const inputPayload: Omit & { - comments?: CommentsArray; - } = { - ...getCreateEndpointListItemSchemaMock(), - comments: [getCommentsMock()], - }; - const decoded = createEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "created_at,created_by,id"']); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an undefined for "entries"', () => { - const inputPayload = getCreateEndpointListItemSchemaMock(); - const outputPayload = getCreateEndpointListItemSchemaMock(); - // @ts-expect-error - delete inputPayload.entries; - outputPayload.entries = []; - const decoded = createEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateEndpointListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should pass validation when supplied an undefined for "tags" but return an array and generate a correct body not counting the auto generated uuid', () => { - const inputPayload = getCreateEndpointListItemSchemaMock(); - const outputPayload = getCreateEndpointListItemSchemaMock(); - delete inputPayload.tags; - outputPayload.tags = []; - const decoded = createEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateEndpointListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should pass validation when supplied an undefined for "item_id" and auto generate a uuid', () => { - const inputPayload = getCreateEndpointListItemSchemaMock(); - delete inputPayload.item_id; - const decoded = createEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as CreateEndpointListItemSchema).item_id).toMatch( - /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i - ); - }); - - test('it should pass validation when supplied an undefined for "item_id" and generate a correct body not counting the uuid', () => { - const inputPayload = getCreateEndpointListItemSchemaMock(); - delete inputPayload.item_id; - const decoded = createEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateEndpointListItemSchema).item_id; - expect(message.schema).toEqual(inputPayload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: CreateEndpointListItemSchema & { - extraKey: string; - } = { ...getCreateEndpointListItemSchemaMock(), extraKey: 'some new value' }; - const decoded = createEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.ts deleted file mode 100644 index f8e3965df733e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { DefaultUuid } from '@kbn/securitysolution-io-ts-types'; -import { nonEmptyEndpointEntriesArray } from '../../common/endpoint/entries'; -import { exceptionListItemType } from '../../common/exception_list_item_type'; -import { DefaultCreateCommentsArray } from '../../common/default_create_comments_array'; -import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { CreateCommentsArray } from '../../common/create_comment'; -import { Tags } from '../../common/tags'; -import { ItemId } from '../../common/item_id'; -import { EntriesArray } from '../../common/entries'; -import { description } from '../../common/description'; -import { name } from '../../common/name'; -import { meta } from '../../common/meta'; -import { tags } from '../../common/tags'; - -export const createEndpointListItemSchema = t.intersection([ - t.exact( - t.type({ - description, - entries: nonEmptyEndpointEntriesArray, - name, - type: exceptionListItemType, - }) - ), - t.exact( - t.partial({ - comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode - item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode - meta, // defaults to undefined if not set during decode - os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode - tags, // defaults to empty array if not set during decode - }) - ), -]); - -export type CreateEndpointListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type CreateEndpointListItemSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'tags' | 'item_id' | 'entries' | 'comments' | 'os_types' -> & { - comments: CreateCommentsArray; - tags: Tags; - item_id: ItemId; - entries: EntriesArray; - os_types: OsTypeArray; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.mock.ts deleted file mode 100644 index 23b3eb19171de..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.mock.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { CreateExceptionListItemSchema } from '.'; -import { - COMMENTS, - DESCRIPTION, - ENTRIES, - ITEM_ID, - ITEM_TYPE, - LIST_ID, - META, - NAME, - NAMESPACE_TYPE, - OS_TYPES, - TAGS, -} from '../../constants/index.mock'; - -export const getCreateExceptionListItemSchemaMock = (): CreateExceptionListItemSchema => ({ - comments: COMMENTS, - description: DESCRIPTION, - entries: ENTRIES, - item_id: undefined, - list_id: LIST_ID, - meta: META, - name: NAME, - namespace_type: NAMESPACE_TYPE, - os_types: OS_TYPES, - tags: TAGS, - type: ITEM_TYPE, -}); - -/** - * Useful for end to end testing - */ -export const getCreateExceptionListItemMinimalSchemaMock = (): CreateExceptionListItemSchema => ({ - description: DESCRIPTION, - entries: ENTRIES, - item_id: ITEM_ID, - list_id: LIST_ID, - name: NAME, - os_types: OS_TYPES, - type: ITEM_TYPE, -}); - -/** - * Useful for end to end testing - */ -export const getCreateExceptionListItemMinimalSchemaMockWithoutId = - (): CreateExceptionListItemSchema => ({ - description: DESCRIPTION, - entries: ENTRIES, - list_id: LIST_ID, - name: NAME, - os_types: OS_TYPES, - type: ITEM_TYPE, - }); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.test.ts deleted file mode 100644 index dc5dcb63cf1b7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.test.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getCreateExceptionListItemSchemaMock } from './index.mock'; -import { CreateExceptionListItemSchema, createExceptionListItemSchema } from '.'; -import { getCreateCommentsArrayMock } from '../../common/create_comment/index.mock'; -import { getCommentsMock } from '../../common/comment/index.mock'; -import { CommentsArray } from '../../common/comment'; - -describe('create_exception_list_item_schema', () => { - test('it should pass validation when supplied a typical exception list item request not counting the auto generated uuid', () => { - const payload = getCreateExceptionListItemSchemaMock(); - const decoded = createExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should fail validation when supplied an undefined for "description"', () => { - const payload = getCreateExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.description; - const decoded = createExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an undefined for "name"', () => { - const payload = getCreateExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.name; - const decoded = createExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an undefined for "type"', () => { - const payload = getCreateExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.type; - const decoded = createExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an undefined for "list_id"', () => { - const inputPayload = getCreateExceptionListItemSchemaMock(); - // @ts-expect-error - delete inputPayload.list_id; - const decoded = createExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should pass validation when supplied an undefined for "meta" but strip it out and generate a correct body not counting the auto generated uuid', () => { - const payload = getCreateExceptionListItemSchemaMock(); - const outputPayload = getCreateExceptionListItemSchemaMock(); - delete payload.meta; - delete outputPayload.meta; - const decoded = createExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should pass validation when supplied an undefined for "comments" but return an array and generate a correct body not counting the auto generated uuid', () => { - const inputPayload = getCreateExceptionListItemSchemaMock(); - const outputPayload = getCreateExceptionListItemSchemaMock(); - delete inputPayload.comments; - outputPayload.comments = []; - const decoded = createExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should pass validation when supplied "comments" array', () => { - const inputPayload = { - ...getCreateExceptionListItemSchemaMock(), - comments: getCreateCommentsArrayMock(), - }; - const decoded = createExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(inputPayload); - }); - - test('it should fail validation when supplied "comments" with "created_at" or "created_by" values', () => { - const inputPayload: Omit & { - comments?: CommentsArray; - } = { - ...getCreateExceptionListItemSchemaMock(), - comments: [getCommentsMock()], - }; - const decoded = createExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "created_at,created_by,id"']); - expect(message.schema).toEqual({}); - }); - - test('it should fail validation when supplied an undefined for "entries"', () => { - const inputPayload = getCreateExceptionListItemSchemaMock(); - const outputPayload = getCreateExceptionListItemSchemaMock(); - // @ts-expect-error - delete inputPayload.entries; - outputPayload.entries = []; - const decoded = createExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should pass validation when supplied an undefined for "namespace_type" but return enum "single" and generate a correct body not counting the auto generated uuid', () => { - const inputPayload = getCreateExceptionListItemSchemaMock(); - const outputPayload = getCreateExceptionListItemSchemaMock(); - delete inputPayload.namespace_type; - outputPayload.namespace_type = 'single'; - const decoded = createExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should pass validation when supplied an undefined for "tags" but return an array and generate a correct body not counting the auto generated uuid', () => { - const inputPayload = getCreateExceptionListItemSchemaMock(); - const outputPayload = getCreateExceptionListItemSchemaMock(); - delete inputPayload.tags; - outputPayload.tags = []; - const decoded = createExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListItemSchema).item_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should pass validation when supplied an undefined for "item_id" and auto generate a uuid', () => { - const inputPayload = getCreateExceptionListItemSchemaMock(); - delete inputPayload.item_id; - const decoded = createExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as CreateExceptionListItemSchema).item_id).toMatch( - /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i - ); - }); - - test('it should pass validation when supplied an undefined for "item_id" and generate a correct body not counting the uuid', () => { - const inputPayload = getCreateExceptionListItemSchemaMock(); - delete inputPayload.item_id; - const decoded = createExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListItemSchema).item_id; - expect(message.schema).toEqual(inputPayload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: CreateExceptionListItemSchema & { - extraKey?: string; - } = getCreateExceptionListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = createExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.ts deleted file mode 100644 index 8445b2d03d677..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { DefaultUuid } from '@kbn/securitysolution-io-ts-types'; - -import { DefaultCreateCommentsArray } from '../../common/default_create_comments_array'; -import { CreateCommentsArray } from '../../common/create_comment'; -import { Tags } from '../../common/tags'; -import { ItemId } from '../../common/item_id'; -import { EntriesArray } from '../../common/entries'; -import { NamespaceType } from '../../common/default_namespace'; -import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { description } from '../../common/description'; -import { list_id } from '../../common/list_id'; -import { name } from '../../common/name'; -import { exceptionListItemType } from '../../common/exception_list_item_type'; -import { meta } from '../../common/meta'; -import { namespace_type } from '../../common/namespace_type'; -import { tags } from '../../common/tags'; -import { nonEmptyEntriesArray } from '../../common/non_empty_entries_array'; -import { ExpireTimeOrUndefined, expireTimeOrUndefined } from '../../common'; - -export const createExceptionListItemSchema = t.intersection([ - t.exact( - t.type({ - description, - entries: nonEmptyEntriesArray, - list_id, - name, - type: exceptionListItemType, - }) - ), - t.exact( - t.partial({ - comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode - expire_time: expireTimeOrUndefined, - item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode - meta, // defaults to undefined if not set during decode - namespace_type, // defaults to 'single' if not set during decode - os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode - tags, // defaults to empty array if not set during decode - }) - ), -]); - -export type CreateExceptionListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type CreateExceptionListItemSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments' | 'expire_time' -> & { - comments: CreateCommentsArray; - expire_time: ExpireTimeOrUndefined; - tags: Tags; - item_id: ItemId; - entries: EntriesArray; - namespace_type: NamespaceType; - os_types: OsTypeArray; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.mock.ts deleted file mode 100644 index 798d36783d7ca..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.mock.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - DESCRIPTION, - ENDPOINT_TYPE, - LIST_ID, - META, - NAME, - NAMESPACE_TYPE, - VERSION, -} from '../../constants/index.mock'; - -import { CreateExceptionListSchema } from '.'; - -export const getCreateExceptionListSchemaMock = (): CreateExceptionListSchema => ({ - description: DESCRIPTION, - list_id: undefined, - meta: META, - name: NAME, - namespace_type: NAMESPACE_TYPE, - os_types: [], - tags: [], - type: ENDPOINT_TYPE, - version: VERSION, -}); - -/** - * Useful for end to end testing - */ -export const getCreateExceptionListMinimalSchemaMock = (): CreateExceptionListSchema => ({ - description: DESCRIPTION, - list_id: LIST_ID, - name: NAME, - type: ENDPOINT_TYPE, -}); - -/** - * Useful for end to end testing - */ -export const getCreateExceptionListMinimalSchemaMockWithoutId = (): CreateExceptionListSchema => ({ - description: DESCRIPTION, - name: NAME, - type: ENDPOINT_TYPE, -}); - -/** - * Useful for end to end testing with detections - */ -export const getCreateExceptionListDetectionSchemaMock = (): CreateExceptionListSchema => ({ - description: DESCRIPTION, - list_id: LIST_ID, - name: NAME, - type: 'detection', -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.test.ts deleted file mode 100644 index f6d164f8786bb..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { CreateExceptionListSchema, createExceptionListSchema } from '.'; -import { getCreateExceptionListSchemaMock } from './index.mock'; - -describe('create_exception_list_schema', () => { - test('it should validate a typical exception lists request and generate a correct body not counting the uuid', () => { - const payload = getCreateExceptionListSchemaMock(); - const decoded = createExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListSchema).list_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "meta" and generate a correct body not counting the uuid', () => { - const payload = getCreateExceptionListSchemaMock(); - delete payload.meta; - const decoded = createExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListSchema).list_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "tags" but return an array and generate a correct body not counting the uuid', () => { - const inputPayload = getCreateExceptionListSchemaMock(); - const outputPayload = getCreateExceptionListSchemaMock(); - delete inputPayload.tags; - outputPayload.tags = []; - const decoded = createExceptionListSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListSchema).list_id; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should accept an undefined for "list_id" and auto generate a uuid', () => { - const inputPayload = getCreateExceptionListSchemaMock(); - delete inputPayload.list_id; - const decoded = createExceptionListSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as CreateExceptionListSchema).list_id).toMatch( - /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i - ); - }); - - test('it should accept an undefined for "list_id" and generate a correct body not counting the uuid', () => { - const inputPayload = getCreateExceptionListSchemaMock(); - delete inputPayload.list_id; - const decoded = createExceptionListSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as CreateExceptionListSchema).list_id; - expect(message.schema).toEqual(inputPayload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: CreateExceptionListSchema & { - extraKey?: string; - } = getCreateExceptionListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = createExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.ts deleted file mode 100644 index 786e39a618641..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { - DefaultUuid, - DefaultVersionNumber, - DefaultVersionNumberDecoded, -} from '@kbn/securitysolution-io-ts-types'; - -import { exceptionListType } from '../../common/exception_list'; -import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { Tags } from '../../common/tags'; -import { ListId } from '../../common/list_id'; -import { NamespaceType } from '../../common/default_namespace'; -import { name } from '../../common/name'; -import { description } from '../../common/description'; -import { namespace_type } from '../../common/namespace_type'; -import { tags } from '../../common/tags'; -import { meta } from '../../common/meta'; - -export const createExceptionListSchema = t.intersection([ - t.exact( - t.type({ - description, - name, - type: exceptionListType, - }) - ), - t.exact( - t.partial({ - list_id: DefaultUuid, // defaults to a GUID (UUID v4) string if not set during decode - meta, // defaults to undefined if not set during decode - namespace_type, // defaults to 'single' if not set during decode - os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode - tags, // defaults to empty array if not set during decode - version: DefaultVersionNumber, // defaults to numerical 1 if not set during decode - }) - ), -]); - -export type CreateExceptionListSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type CreateExceptionListSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'tags' | 'list_id' | 'namespace_type' | 'os_types' -> & { - tags: Tags; - list_id: ListId; - namespace_type: NamespaceType; - os_types: OsTypeArray; - version: DefaultVersionNumberDecoded; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.mock.ts deleted file mode 100644 index ed9a77fb859ae..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.mock.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { LIST_ID, LIST_ITEM_ID, META, VALUE } from '../../constants/index.mock'; - -import { CreateListItemSchema } from '.'; - -export const getCreateListItemSchemaMock = (): CreateListItemSchema => ({ - id: LIST_ITEM_ID, - list_id: LIST_ID, - meta: META, - value: VALUE, -}); - -/** - * Useful for end to end testing - */ -export const getCreateMinimalListItemSchemaMock = (): CreateListItemSchema => ({ - id: LIST_ITEM_ID, - list_id: LIST_ID, - value: VALUE, -}); - -/** - * Useful for end to end testing - */ -export const getCreateMinimalListItemSchemaMockWithoutId = (): CreateListItemSchema => ({ - list_id: LIST_ID, - value: VALUE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.test.ts deleted file mode 100644 index 3e991933b664c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getCreateListItemSchemaMock } from './index.mock'; -import { CreateListItemSchema, createListItemSchema } from '.'; - -describe('create_list_item_schema', () => { - test('it should validate a typical list item request', () => { - const payload = getCreateListItemSchemaMock(); - const decoded = createListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for an id', () => { - const payload = getCreateListItemSchemaMock(); - delete payload.id; - const decoded = createListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for meta', () => { - const payload = getCreateListItemSchemaMock(); - delete payload.meta; - const decoded = createListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: CreateListItemSchema & { extraKey?: string } = getCreateListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = createListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.ts deleted file mode 100644 index f1b3c65865357..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { list_id } from '../../common/list_id'; -import { value } from '../../common/value'; -import { id } from '../../common/id'; -import { meta } from '../../common/meta'; -import { refreshWithWaitFor } from '../../common/refresh'; - -export const createListItemSchema = t.intersection([ - t.exact( - t.type({ - list_id, - value, - }) - ), - t.exact(t.partial({ id, meta, refresh: refreshWithWaitFor })), -]); - -export type CreateListItemSchema = t.OutputOf; -export type CreateListItemSchemaDecoded = RequiredKeepUndefined< - t.TypeOf ->; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.mock.ts deleted file mode 100644 index bbdd927a58e74..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.mock.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DESCRIPTION, LIST_ID, META, NAME, TYPE, VERSION } from '../../constants/index.mock'; - -import { CreateListSchema } from '.'; - -export const getCreateListSchemaMock = (): CreateListSchema => ({ - description: DESCRIPTION, - deserializer: undefined, - id: LIST_ID, - meta: META, - name: NAME, - serializer: undefined, - type: TYPE, - version: VERSION, -}); - -/** - * Useful for end to end tests and other mechanisms which want to fill in the values - */ -export const getCreateMinimalListSchemaMock = (): CreateListSchema => ({ - description: DESCRIPTION, - id: LIST_ID, - name: NAME, - type: TYPE, -}); - -/** - * Useful for end to end tests and other mechanisms which want to fill in the values - */ -export const getCreateMinimalListSchemaMockWithoutId = (): CreateListSchema => ({ - description: DESCRIPTION, - name: NAME, - type: TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.test.ts deleted file mode 100644 index 0eb9ecd02505f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { CreateListSchema, createListSchema } from '.'; -import { getCreateListSchemaMock } from './index.mock'; - -describe('create_list_schema', () => { - test('it should validate a typical lists request', () => { - const payload = getCreateListSchemaMock(); - const decoded = createListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for an id', () => { - const payload = getCreateListSchemaMock(); - delete payload.id; - const decoded = createListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for meta', () => { - const payload = getCreateListSchemaMock(); - delete payload.meta; - const decoded = createListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for serializer', () => { - const payload = getCreateListSchemaMock(); - delete payload.serializer; - const decoded = createListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for deserializer', () => { - const payload = getCreateListSchemaMock(); - delete payload.deserializer; - const decoded = createListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: CreateListSchema & { extraKey?: string } = getCreateListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = createListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.ts deleted file mode 100644 index c6e210a999ea7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { - DefaultVersionNumber, - DefaultVersionNumberDecoded, -} from '@kbn/securitysolution-io-ts-types'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { name } from '../../common/name'; -import { description } from '../../common/description'; -import { type } from '../../common/type'; -import { deserializer } from '../../common/deserializer'; -import { id } from '../../common/id'; -import { meta } from '../../common/meta'; -import { serializer } from '../../common/serializer'; - -export const createListSchema = t.intersection([ - t.exact( - t.type({ - description, - name, - type, - }) - ), - t.exact( - t.partial({ - deserializer, // defaults to undefined if not set during decode - id, // defaults to undefined if not set during decode - meta, // defaults to undefined if not set during decode - serializer, // defaults to undefined if not set during decode - version: DefaultVersionNumber, // defaults to a numerical 1 if not set during decode - }) - ), -]); - -export type CreateListSchema = t.OutputOf; -export type CreateListSchemaDecoded = RequiredKeepUndefined< - Omit, 'version'> -> & { version: DefaultVersionNumberDecoded }; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.test.ts deleted file mode 100644 index 1eda590adb5de..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { CreateRuleExceptionListItemSchema, createRuleExceptionListItemSchema } from '.'; -import { CreateExceptionListItemSchema } from '../create_exception_list_item_schema'; - -const getCreateExceptionListItemSchemaMock = (): CreateExceptionListItemSchema => ({ - comments: [], - description: 'some description', - entries: [ - { - field: 'host.name', - operator: 'included', - type: 'match_any', - value: ['foo', 'bar'], - }, - ], - item_id: undefined, - list_id: 'some-list-id', - name: 'some name', - namespace_type: 'single', - os_types: [], - tags: [], - type: 'simple', -}); - -describe('createRuleExceptionListItemSchema', () => { - test('empty objects do not validate', () => { - const payload = {} as CreateRuleExceptionListItemSchema; - - const decoded = createRuleExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - 'Invalid value "undefined" supplied to "entries"', - 'Invalid value "undefined" supplied to "name"', - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('items without list_id validate', () => { - const payload: CreateRuleExceptionListItemSchema = { - description: 'Exception item for rule default exception list', - entries: [ - { - field: 'some.not.nested.field', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - name: 'Sample exception item', - type: 'simple', - }; - - const decoded = createRuleExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual( - expect.objectContaining({ - comments: [], - description: 'Exception item for rule default exception list', - entries: [ - { - field: 'some.not.nested.field', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - name: 'Sample exception item', - os_types: [], - tags: [], - type: 'simple', - }) - ); - }); - - test('items with list_id do not validate', () => { - const payload = - getCreateExceptionListItemSchemaMock() as unknown as CreateRuleExceptionListItemSchema; - - const decoded = createRuleExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some-list-id" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('made up parameters do not validate', () => { - const payload: Partial & { madeUp: string } = { - description: 'Exception item for rule default exception list', - entries: [ - { - field: 'some.not.nested.field', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - name: 'Sample exception item', - type: 'simple', - madeUp: 'invalid value', - }; - - const decoded = createRuleExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.ts deleted file mode 100644 index 1e4a254f92b81..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { DefaultUuid } from '@kbn/securitysolution-io-ts-types'; - -import { - CreateCommentsArray, - DefaultCreateCommentsArray, - description, - EntriesArray, - exceptionListItemType, - ItemId, - meta, - NamespaceType, - namespaceType, - nonEmptyEntriesArray, - OsTypeArray, - osTypeArrayOrUndefined, - Tags, - tags, - name, - ExpireTimeOrUndefined, - expireTimeOrUndefined, -} from '../../common'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; - -export const createRuleExceptionListItemSchema = t.intersection([ - t.exact( - t.type({ - description, - entries: nonEmptyEntriesArray, - name, - type: exceptionListItemType, - }) - ), - t.exact( - t.partial({ - comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode - item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode - list_id: t.undefined, - meta, // defaults to undefined if not set during decode - namespace_type: namespaceType, // defaults to 'single' if not set during decode - os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode - tags, // defaults to empty array if not set during decode - expire_time: expireTimeOrUndefined, - }) - ), -]); - -export type CreateRuleExceptionListItemSchema = t.OutputOf< - typeof createRuleExceptionListItemSchema ->; - -// This type is used after a decode since some things are defaults after a decode. -export type CreateRuleExceptionListItemSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments' | 'expire_time' -> & { - comments: CreateCommentsArray; - tags: Tags; - item_id: ItemId; - entries: EntriesArray; - namespace_type: NamespaceType; - os_types: OsTypeArray; - expire_time: ExpireTimeOrUndefined; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.mock.ts deleted file mode 100644 index 2f7963171197f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.mock.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ID } from '../../constants/index.mock'; - -import { DeleteEndpointListItemSchema } from '.'; - -export const getDeleteEndpointListItemSchemaMock = (): DeleteEndpointListItemSchema => ({ - id: ID, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.test.ts deleted file mode 100644 index d702632713a59..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { DeleteEndpointListItemSchema, deleteEndpointListItemSchema } from '.'; -import { getDeleteEndpointListItemSchemaMock } from './index.mock'; - -describe('delete_endpoint_list_item_schema', () => { - test('it should validate a typical endpoint list item request', () => { - const payload = getDeleteEndpointListItemSchemaMock(); - const decoded = deleteEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept a value for "namespace_type" since it does not require one', () => { - const payload: DeleteEndpointListItemSchema & { - namespace_type: string; - } = { ...getDeleteEndpointListItemSchemaMock(), namespace_type: 'single' }; - // @ts-expect-error - delete payload.namespace_type; - const decoded = deleteEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getDeleteEndpointListItemSchemaMock()); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: DeleteEndpointListItemSchema & { - extraKey?: string; - } = { ...getDeleteEndpointListItemSchemaMock(), extraKey: 'some new value' }; - const decoded = deleteEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.ts deleted file mode 100644 index f968b1410a25d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { id } from '../../common/id'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { item_id } from '../../common/item_id'; - -export const deleteEndpointListItemSchema = t.exact( - t.partial({ - id, - item_id, - }) -); - -export type DeleteEndpointListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type DeleteEndpointListItemSchemaDecoded = RequiredKeepUndefined< - t.TypeOf ->; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.mock.ts deleted file mode 100644 index 723b5acb6620c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.mock.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ID, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { DeleteExceptionListItemSchema } from '.'; - -export const getDeleteExceptionListItemSchemaMock = (): DeleteExceptionListItemSchema => ({ - id: ID, - namespace_type: NAMESPACE_TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.test.ts deleted file mode 100644 index 375fc20ba4da4..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { DeleteExceptionListItemSchema, deleteExceptionListItemSchema } from '.'; -import { getDeleteExceptionListItemSchemaMock } from './index.mock'; - -describe('delete_exception_list_item_schema', () => { - test('it should validate a typical exception list item request', () => { - const payload = getDeleteExceptionListItemSchemaMock(); - const decoded = deleteExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "namespace_type" but default to "single"', () => { - const payload = getDeleteExceptionListItemSchemaMock(); - delete payload.namespace_type; - const decoded = deleteExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getDeleteExceptionListItemSchemaMock()); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: DeleteExceptionListItemSchema & { - extraKey?: string; - } = getDeleteExceptionListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = deleteExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.ts deleted file mode 100644 index 4d961aa9e1a5b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { NamespaceType } from '../../common/default_namespace'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { item_id } from '../../common/item_id'; -import { namespace_type } from '../../common/namespace_type'; - -export const deleteExceptionListItemSchema = t.exact( - t.partial({ - id, - item_id, - namespace_type, // defaults to 'single' if not set during decode - }) -); - -export type DeleteExceptionListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type DeleteExceptionListItemSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'namespace_type' -> & { - namespace_type: NamespaceType; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.mock.ts deleted file mode 100644 index f41f5b288004b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.mock.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ID, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { DeleteExceptionListSchema } from '.'; - -export const getDeleteExceptionListSchemaMock = (): DeleteExceptionListSchema => ({ - id: ID, - namespace_type: NAMESPACE_TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.test.ts deleted file mode 100644 index 5507f855d783a..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { DeleteExceptionListSchema, deleteExceptionListSchema } from '.'; -import { getDeleteExceptionListSchemaMock } from './index.mock'; - -describe('delete_exception_list_schema', () => { - test('it should validate a typical exception list request', () => { - const payload = getDeleteExceptionListSchemaMock(); - const decoded = deleteExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "namespace_type" but default to "single"', () => { - const payload = getDeleteExceptionListSchemaMock(); - delete payload.namespace_type; - const decoded = deleteExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getDeleteExceptionListSchemaMock()); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: DeleteExceptionListSchema & { - extraKey?: string; - } = getDeleteExceptionListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = deleteExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.ts deleted file mode 100644 index 62855c9dc212d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { NamespaceType } from '../../common/default_namespace'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { list_id } from '../../common/list_id'; -import { namespace_type } from '../../common/namespace_type'; - -export const deleteExceptionListSchema = t.exact( - t.partial({ - id, - list_id, - namespace_type, // defaults to 'single' if not set during decode - }) -); - -export type DeleteExceptionListSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type DeleteExceptionListSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'namespace_type' -> & { - namespace_type: NamespaceType; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.mock.ts deleted file mode 100644 index aaa03621d676f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ID, LIST_ID, VALUE } from '../../constants/index.mock'; - -import { DeleteListItemSchema } from '.'; - -export const getDeleteListItemSchemaMock = (): DeleteListItemSchema => ({ - id: ID, - list_id: LIST_ID, - value: VALUE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.test.ts deleted file mode 100644 index d838fbab4f162..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { DeleteListItemSchema, deleteListItemSchema } from '.'; -import { getDeleteListItemSchemaMock } from './index.mock'; - -describe('delete_list_item_schema', () => { - test('it should validate a typical list item request', () => { - const payload = getDeleteListItemSchemaMock(); - const decoded = deleteListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: DeleteListItemSchema & { - extraKey?: string; - } = { ...getDeleteListItemSchemaMock(), extraKey: 'some new value' }; - const decoded = deleteListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.ts deleted file mode 100644 index bbf0a09a15c81..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { list_id } from '../../common/list_id'; -import { valueOrUndefined } from '../../common/value'; -import { refresh } from '../../common/refresh'; - -export const deleteListItemSchema = t.intersection([ - t.exact( - t.type({ - value: valueOrUndefined, - }) - ), - t.exact(t.partial({ id, list_id, refresh })), -]); - -export type DeleteListItemSchema = t.OutputOf; -export type DeleteListItemSchemaDecoded = RequiredKeepUndefined< - t.TypeOf ->; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.mock.ts deleted file mode 100644 index 4514b70ad39fe..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { LIST_ID } from '../../constants/index.mock'; - -import { DeleteListSchema } from '.'; - -export const getDeleteListSchemaMock = (): DeleteListSchema => ({ - deleteReferences: false, - id: LIST_ID, - ignoreReferences: true, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.test.ts deleted file mode 100644 index 5de3ec2c21097..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { DeleteListSchema, deleteListSchema } from '.'; -import { getDeleteListSchemaMock } from './index.mock'; - -describe('delete_list_schema', () => { - test('it should validate a typical lists request', () => { - const payload = getDeleteListSchemaMock(); - const decoded = deleteListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for an id', () => { - const payload = getDeleteListSchemaMock(); - // @ts-expect-error - delete payload.id; - const decoded = deleteListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: DeleteListSchema & { extraKey?: string } = getDeleteListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = deleteListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.ts deleted file mode 100644 index 239a4d72113d7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { DefaultStringBooleanFalse } from '@kbn/securitysolution-io-ts-types'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; - -export const deleteListSchema = t.intersection([ - t.exact( - t.type({ - id, - }) - ), - t.exact( - t.partial({ - deleteReferences: DefaultStringBooleanFalse, - ignoreReferences: DefaultStringBooleanFalse, - }) - ), -]); - -export type DeleteListSchema = RequiredKeepUndefined>; -export type DeleteListSchemaEncoded = t.OutputOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.mock.ts deleted file mode 100644 index 121ab5f0b914e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { DuplicateExceptionListQuerySchema } from '.'; - -export const getDuplicateExceptionListQuerySchemaMock = (): DuplicateExceptionListQuerySchema => ({ - list_id: LIST_ID, - namespace_type: NAMESPACE_TYPE, - include_expired_exceptions: 'true', -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.test.ts deleted file mode 100644 index 244adc07a81d8..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { DuplicateExceptionListQuerySchema, duplicateExceptionListQuerySchema } from '.'; -import { getDuplicateExceptionListQuerySchemaMock } from './index.mock'; - -describe('duplicate_exceptionList_query_schema', () => { - test('it should validate a typical lists request', () => { - const payload = getDuplicateExceptionListQuerySchemaMock(); - const decoded = duplicateExceptionListQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should default namespace_type to "single" if an undefined given for namespacetype', () => { - const payload = getDuplicateExceptionListQuerySchemaMock(); - delete payload.namespace_type; - const decoded = duplicateExceptionListQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(message.schema).toEqual({ - include_expired_exceptions: 'true', - list_id: 'some-list-id', - namespace_type: 'single', - }); - }); - - test('it should NOT accept an undefined for an list_id', () => { - const payload = getDuplicateExceptionListQuerySchemaMock(); - // @ts-expect-error - delete payload.list_id; - const decoded = duplicateExceptionListQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: DuplicateExceptionListQuerySchema & { - extraKey?: string; - } = getDuplicateExceptionListQuerySchemaMock(); - payload.extraKey = 'some new value'; - const decoded = duplicateExceptionListQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.ts deleted file mode 100644 index b329e1244eb90..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { NamespaceType } from '../../common'; - -import { includeExpiredExceptionsOrUndefined } from '../../common/include_expired_exceptions'; -import { list_id } from '../../common/list_id'; -import { namespace_type } from '../../common/namespace_type'; - -export const duplicateExceptionListQuerySchema = t.exact( - t.type({ - list_id, - namespace_type, - include_expired_exceptions: includeExpiredExceptionsOrUndefined, - }) -); - -export type DuplicateExceptionListQuerySchema = t.OutputOf< - typeof duplicateExceptionListQuerySchema ->; - -// This type is used after a decode since some things are defaults after a decode. -export type DuplicateExceptionListQuerySchemaDecoded = Omit< - t.TypeOf, - 'namespace_type' -> & { - namespace_type: NamespaceType; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.mock.ts deleted file mode 100644 index 4f34a59407eae..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.mock.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ID, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { ExportExceptionListQuerySchema } from '.'; - -export const getExportExceptionListQuerySchemaMock = (): ExportExceptionListQuerySchema => ({ - id: ID, - list_id: LIST_ID, - namespace_type: NAMESPACE_TYPE, - include_expired_exceptions: 'true', -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.test.ts deleted file mode 100644 index 00b41f6d70f99..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { ExportExceptionListQuerySchema, exportExceptionListQuerySchema } from '.'; -import { getExportExceptionListQuerySchemaMock } from './index.mock'; - -describe('export_exception_list_schema', () => { - test('it should validate a typical lists request', () => { - const payload = getExportExceptionListQuerySchemaMock(); - const decoded = exportExceptionListQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for an id', () => { - const payload = getExportExceptionListQuerySchemaMock(); - // @ts-expect-error - delete payload.id; - const decoded = exportExceptionListQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should default namespace_type to "single" if an undefined given for namespacetype', () => { - const payload = getExportExceptionListQuerySchemaMock(); - delete payload.namespace_type; - const decoded = exportExceptionListQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(message.schema).toEqual({ - id: 'uuid_here', - include_expired_exceptions: 'true', - list_id: 'some-list-id', - namespace_type: 'single', - }); - }); - - test('it should NOT accept an undefined for an list_id', () => { - const payload = getExportExceptionListQuerySchemaMock(); - // @ts-expect-error - delete payload.list_id; - const decoded = exportExceptionListQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ExportExceptionListQuerySchema & { - extraKey?: string; - } = getExportExceptionListQuerySchemaMock(); - payload.extraKey = 'some new value'; - const decoded = exportExceptionListQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.ts deleted file mode 100644 index 3943af148b159..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { id } from '../../common/id'; -import { includeExpiredExceptionsOrUndefined } from '../../common/include_expired_exceptions'; -import { list_id } from '../../common/list_id'; -import { namespace_type } from '../../common/namespace_type'; - -export const exportExceptionListQuerySchema = t.exact( - t.type({ - id, - list_id, - namespace_type, - include_expired_exceptions: includeExpiredExceptionsOrUndefined, - // TODO: Add file_name here with a default value - }) -); - -export type ExportExceptionListQuerySchema = t.OutputOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.mock.ts deleted file mode 100644 index 3c66cae1fb0ee..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.mock.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { LIST_ID } from '../../constants/index.mock'; - -import { ExportListItemQuerySchema } from '.'; - -export const getExportListItemQuerySchemaMock = (): ExportListItemQuerySchema => ({ - list_id: LIST_ID, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.test.ts deleted file mode 100644 index 55713e33f1600..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { ExportListItemQuerySchema, exportListItemQuerySchema } from '.'; -import { getExportListItemQuerySchemaMock } from './index.mock'; - -describe('export_list_item_schema', () => { - test('it should validate a typical lists request', () => { - const payload = getExportListItemQuerySchemaMock(); - const decoded = exportListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for an id', () => { - const payload = getExportListItemQuerySchemaMock(); - // @ts-expect-error - delete payload.list_id; - const decoded = exportListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ExportListItemQuerySchema & { - extraKey?: string; - } = getExportListItemQuerySchemaMock(); - payload.extraKey = 'some new value'; - const decoded = exportListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.ts deleted file mode 100644 index 86c8318f1ad5c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { list_id } from '../../common/list_id'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; - -export const exportListItemQuerySchema = t.exact( - t.type({ - list_id, - // TODO: Add file_name here with a default value - }) -); - -export type ExportListItemQuerySchema = RequiredKeepUndefined< - t.TypeOf ->; -export type ExportListItemQuerySchemaEncoded = t.OutputOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.mock.ts deleted file mode 100644 index d24d31cca5d98..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.mock.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FILTER } from '../../constants/index.mock'; - -import { FindEndpointListItemSchema, FindEndpointListItemSchemaDecoded } from '.'; - -export const getFindEndpointListItemSchemaMock = (): FindEndpointListItemSchema => ({ - filter: FILTER, - page: '1', - per_page: '25', - sort_field: undefined, - sort_order: undefined, -}); - -export const getFindEndpointListItemSchemaDecodedMock = (): FindEndpointListItemSchemaDecoded => ({ - filter: FILTER, - page: 1, - per_page: 25, - sort_field: undefined, - sort_order: undefined, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.test.ts deleted file mode 100644 index 776cc2976868d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.test.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { - getFindEndpointListItemSchemaDecodedMock, - getFindEndpointListItemSchemaMock, -} from './index.mock'; -import { FindEndpointListItemSchema, findEndpointListItemSchema } from '.'; - -describe('find_endpoint_list_item_schema', () => { - test('it should validate a typical find item request', () => { - const payload = getFindEndpointListItemSchemaMock(); - const decoded = findEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getFindEndpointListItemSchemaDecodedMock()); - }); - - test('it should validate and empty object since everything is optional and has defaults', () => { - const payload: FindEndpointListItemSchema = {}; - const decoded = findEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate with page missing', () => { - const payload = getFindEndpointListItemSchemaMock(); - delete payload.page; - const decoded = findEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindEndpointListItemSchemaDecodedMock(); - delete expected.page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with pre_page missing', () => { - const payload = getFindEndpointListItemSchemaMock(); - delete payload.per_page; - const decoded = findEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindEndpointListItemSchemaDecodedMock(); - delete expected.per_page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with filter missing', () => { - const payload = getFindEndpointListItemSchemaMock(); - delete payload.filter; - const decoded = findEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindEndpointListItemSchemaDecodedMock(); - delete expected.filter; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_field missing', () => { - const payload = getFindEndpointListItemSchemaMock(); - delete payload.sort_field; - const decoded = findEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindEndpointListItemSchemaDecodedMock(); - delete expected.sort_field; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_order missing', () => { - const payload = getFindEndpointListItemSchemaMock(); - delete payload.sort_order; - const decoded = findEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindEndpointListItemSchemaDecodedMock(); - delete expected.sort_order; - expect(message.schema).toEqual(expected); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: FindEndpointListItemSchema & { - extraKey: string; - } = { ...getFindEndpointListItemSchemaMock(), extraKey: 'some new value' }; - const decoded = findEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.ts deleted file mode 100644 index a76854d3b4bfc..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { StringToPositiveNumber } from '@kbn/securitysolution-io-ts-types'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { filter } from '../../common/filter'; -import { sort_field } from '../../common/sort_field'; -import { sort_order } from '../../common/sort_order'; - -export const findEndpointListItemSchema = t.exact( - t.partial({ - filter, // defaults to undefined if not set during decode - page: StringToPositiveNumber, // defaults to undefined if not set during decode - per_page: StringToPositiveNumber, // defaults to undefined if not set during decode - sort_field, // defaults to undefined if not set during decode - sort_order, // defaults to undefined if not set during decode - }) -); - -export type FindEndpointListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type FindEndpointListItemSchemaDecoded = RequiredKeepUndefined< - t.TypeOf ->; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.mock.ts deleted file mode 100644 index 02b89bdf4c730..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.mock.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FILTER, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { FindExceptionListItemSchema, FindExceptionListItemSchemaDecoded } from '.'; - -export const getFindExceptionListItemSchemaMock = (): FindExceptionListItemSchema => ({ - filter: FILTER, - list_id: LIST_ID, - namespace_type: NAMESPACE_TYPE, - page: '1', - per_page: '25', - search: undefined, - sort_field: undefined, - sort_order: undefined, -}); - -export const getFindExceptionListItemSchemaMultipleMock = (): FindExceptionListItemSchema => ({ - filter: 'name:Sofia Kovalevskaya,name:Hypatia,name:Sophie Germain', - list_id: 'list-1,list-2,list-3', - namespace_type: 'single,single,agnostic', - page: '1', - per_page: '25', - search: undefined, - sort_field: undefined, - sort_order: undefined, -}); - -export const getFindExceptionListItemSchemaDecodedMock = - (): FindExceptionListItemSchemaDecoded => ({ - filter: [FILTER], - list_id: [LIST_ID], - namespace_type: [NAMESPACE_TYPE], - page: 1, - per_page: 25, - search: undefined, - sort_field: undefined, - sort_order: undefined, - }); - -export const getFindExceptionListItemSchemaDecodedMultipleMock = - (): FindExceptionListItemSchemaDecoded => ({ - filter: ['name:Sofia Kovalevskaya', 'name:Hypatia', 'name:Sophie Germain'], - list_id: ['list-1', 'list-2', 'list-3'], - namespace_type: ['single', 'single', 'agnostic'], - page: 1, - per_page: 25, - search: undefined, - sort_field: undefined, - sort_order: undefined, - }); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.test.ts deleted file mode 100644 index da9c98d48e62b..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.test.ts +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { LIST_ID } from '../../constants/index.mock'; - -import { - getFindExceptionListItemSchemaDecodedMock, - getFindExceptionListItemSchemaDecodedMultipleMock, - getFindExceptionListItemSchemaMock, - getFindExceptionListItemSchemaMultipleMock, -} from './index.mock'; -import { - FindExceptionListItemSchema, - FindExceptionListItemSchemaDecoded, - findExceptionListItemSchema, -} from '.'; - -describe('find_list_item_schema', () => { - test('it should validate a typical find item request', () => { - const payload = getFindExceptionListItemSchemaMock(); - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getFindExceptionListItemSchemaDecodedMock()); - }); - - test('it should validate a typical find item request with multiple input strings turned into array elements', () => { - const payload = getFindExceptionListItemSchemaMultipleMock(); - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getFindExceptionListItemSchemaDecodedMultipleMock()); - }); - - test('it should validate just a list_id where it decodes into an array for list_id and adds a namespace_type of "single" as an array', () => { - const payload: FindExceptionListItemSchema = { list_id: LIST_ID }; - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: FindExceptionListItemSchemaDecoded = { - filter: [], - list_id: [LIST_ID], - namespace_type: ['single'], - page: undefined, - per_page: undefined, - search: undefined, - sort_field: undefined, - sort_order: undefined, - }; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with page missing', () => { - const payload = getFindExceptionListItemSchemaMock(); - delete payload.page; - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListItemSchemaDecodedMock(); - delete expected.page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with per_page missing', () => { - const payload = getFindExceptionListItemSchemaMock(); - delete payload.per_page; - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListItemSchemaDecodedMock(); - delete expected.per_page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with filter missing and add filter as an empty array', () => { - const payload = getFindExceptionListItemSchemaMock(); - delete payload.filter; - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: FindExceptionListItemSchemaDecoded = { - ...getFindExceptionListItemSchemaDecodedMock(), - filter: [], - }; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_field missing', () => { - const payload = getFindExceptionListItemSchemaMock(); - delete payload.sort_field; - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListItemSchemaDecodedMock(); - delete expected.sort_field; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_order missing', () => { - const payload = getFindExceptionListItemSchemaMock(); - delete payload.sort_order; - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListItemSchemaDecodedMock(); - delete expected.sort_order; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with search missing', () => { - const payload = getFindExceptionListItemSchemaMock(); - delete payload.search; - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListItemSchemaDecodedMock(); - delete expected.search; - expect(message.schema).toEqual(expected); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: FindExceptionListItemSchema & { - extraKey: string; - } = { ...getFindExceptionListItemSchemaMock(), extraKey: 'some new value' }; - const decoded = findExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.ts deleted file mode 100644 index 88258538e0311..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { - EmptyStringArray, - EmptyStringArrayDecoded, - NonEmptyStringArray, - StringToPositiveNumber, -} from '@kbn/securitysolution-io-ts-types'; - -import { - DefaultNamespaceArray, - DefaultNamespaceArrayTypeDecoded, -} from '../../common/default_namespace_array'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { sort_field } from '../../common/sort_field'; -import { sort_order } from '../../common/sort_order'; -import { search } from '../../common/search'; - -export const findExceptionListItemSchema = t.intersection([ - t.exact( - t.type({ - list_id: NonEmptyStringArray, - }) - ), - t.exact( - t.partial({ - filter: EmptyStringArray, // defaults to an empty array [] if not set during decode - namespace_type: DefaultNamespaceArray, // defaults to ['single'] if not set during decode - page: StringToPositiveNumber, // defaults to undefined if not set during decode - per_page: StringToPositiveNumber, // defaults to undefined if not set during decode - search, - sort_field, // defaults to undefined if not set during decode - sort_order, // defaults to undefined if not set during decode - }) - ), -]); - -export type FindExceptionListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type FindExceptionListItemSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'namespace_type' | 'filter' -> & { - filter: EmptyStringArrayDecoded; - namespace_type: DefaultNamespaceArrayTypeDecoded; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.mock.ts deleted file mode 100644 index 0b8c9e3db9bb1..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.mock.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FILTER, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { FindExceptionListSchema, FindExceptionListSchemaDecoded } from '.'; - -export const getFindExceptionListSchemaMock = (): FindExceptionListSchema => ({ - filter: FILTER, - namespace_type: NAMESPACE_TYPE, - page: '1', - per_page: '25', - sort_field: undefined, - sort_order: undefined, -}); - -export const getFindExceptionListSchemaDecodedMock = (): FindExceptionListSchemaDecoded => ({ - filter: FILTER, - namespace_type: [NAMESPACE_TYPE], - page: 1, - per_page: 25, - sort_field: undefined, - sort_order: undefined, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.test.ts deleted file mode 100644 index fd105d3d2f61e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { - getFindExceptionListSchemaDecodedMock, - getFindExceptionListSchemaMock, -} from './index.mock'; -import { - FindExceptionListSchema, - FindExceptionListSchemaDecoded, - findExceptionListSchema, -} from '.'; - -describe('find_exception_list_schema', () => { - test('it should validate a typical find item request', () => { - const payload = getFindExceptionListSchemaMock(); - const decoded = findExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getFindExceptionListSchemaDecodedMock()); - }); - - test('it should validate and empty object since everything is optional and will respond only with namespace_type filled out to be "single"', () => { - const payload: FindExceptionListSchema = {}; - const decoded = findExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: FindExceptionListSchemaDecoded = { - filter: undefined, - namespace_type: ['single'], - page: undefined, - per_page: undefined, - sort_field: undefined, - sort_order: undefined, - }; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with page missing', () => { - const payload = getFindExceptionListSchemaMock(); - delete payload.page; - const decoded = findExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListSchemaDecodedMock(); - delete expected.page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with pre_page missing', () => { - const payload = getFindExceptionListSchemaMock(); - delete payload.per_page; - const decoded = findExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListSchemaDecodedMock(); - delete expected.per_page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with filter missing', () => { - const payload = getFindExceptionListSchemaMock(); - delete payload.filter; - const decoded = findExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListSchemaDecodedMock(); - delete expected.filter; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_field missing', () => { - const payload = getFindExceptionListSchemaMock(); - delete payload.sort_field; - const decoded = findExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListSchemaDecodedMock(); - delete expected.sort_field; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_order missing', () => { - const payload = getFindExceptionListSchemaMock(); - delete payload.sort_order; - const decoded = findExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindExceptionListSchemaDecodedMock(); - delete expected.sort_order; - expect(message.schema).toEqual(expected); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: FindExceptionListSchema & { - extraKey: string; - } = { ...getFindExceptionListSchemaMock(), extraKey: 'some new value' }; - const decoded = findExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.ts deleted file mode 100644 index 1e22f752d0142..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { StringToPositiveNumber } from '@kbn/securitysolution-io-ts-types'; - -import { DefaultNamespaceArray, NamespaceTypeArray } from '../../common/default_namespace_array'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { filter } from '../../common/filter'; -import { sort_field } from '../../common/sort_field'; -import { sort_order } from '../../common/sort_order'; - -export const findExceptionListSchema = t.exact( - t.partial({ - filter, // defaults to undefined if not set during decode - namespace_type: DefaultNamespaceArray, // defaults to 'single' if not set during decode - page: StringToPositiveNumber, // defaults to undefined if not set during decode - per_page: StringToPositiveNumber, // defaults to undefined if not set during decode - sort_field, // defaults to undefined if not set during decode - sort_order, // defaults to undefined if not set during decode - }) -); - -export type FindExceptionListSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type FindExceptionListSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'namespace_type' -> & { - namespace_type: NamespaceTypeArray; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.mock.ts deleted file mode 100644 index 601406ce3e37e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.mock.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { CURSOR, FILTER, LIST_ID } from '../../constants/index.mock'; - -import { FindListItemSchema, FindListItemSchemaDecoded } from '.'; - -export const getFindListItemSchemaMock = (): FindListItemSchema => ({ - cursor: CURSOR, - filter: FILTER, - list_id: LIST_ID, - page: '1', - per_page: '25', - sort_field: undefined, - sort_order: undefined, -}); - -export const getFindListItemSchemaDecodedMock = (): FindListItemSchemaDecoded => ({ - cursor: CURSOR, - filter: FILTER, - list_id: LIST_ID, - page: 1, - per_page: 25, - sort_field: undefined, - sort_order: undefined, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.test.ts deleted file mode 100644 index b80629f8546b5..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.test.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { LIST_ID } from '../../constants/index.mock'; - -import { FindListItemSchema, FindListItemSchemaDecoded, findListItemSchema } from '.'; -import { getFindListItemSchemaDecodedMock, getFindListItemSchemaMock } from './index.mock'; - -describe('find_list_item_schema', () => { - test('it should validate a typical find item request', () => { - const payload = getFindListItemSchemaMock(); - const decoded = findListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getFindListItemSchemaDecodedMock()); - }); - - test('it should validate just a list_id where it decodes into an array for list_id and adds a namespace_type of "single"', () => { - const payload: FindListItemSchema = { list_id: LIST_ID }; - const decoded = findListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: FindListItemSchemaDecoded = { - cursor: undefined, - filter: undefined, - list_id: LIST_ID, - page: undefined, - per_page: undefined, - sort_field: undefined, - sort_order: undefined, - }; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with page missing', () => { - const payload = getFindListItemSchemaMock(); - delete payload.page; - const decoded = findListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindListItemSchemaDecodedMock(); - delete expected.page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with pre_page missing', () => { - const payload = getFindListItemSchemaMock(); - delete payload.per_page; - const decoded = findListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindListItemSchemaDecodedMock(); - delete expected.per_page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_field missing', () => { - const payload = getFindListItemSchemaMock(); - delete payload.sort_field; - const decoded = findListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindListItemSchemaDecodedMock(); - delete expected.sort_field; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_order missing', () => { - const payload = getFindListItemSchemaMock(); - delete payload.sort_order; - const decoded = findListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindListItemSchemaDecodedMock(); - delete expected.sort_order; - expect(message.schema).toEqual(expected); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: FindListItemSchema & { - extraKey: string; - } = { ...getFindListItemSchemaMock(), extraKey: 'some new value' }; - const decoded = findListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.ts deleted file mode 100644 index 4509f6bc973bf..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { StringToPositiveNumber } from '@kbn/securitysolution-io-ts-types'; -import { filter } from '../../common/filter'; -import { cursor } from '../../common/cursor'; -import { sort_field } from '../../common/sort_field'; -import { sort_order } from '../../common/sort_order'; -import { list_id } from '../../common/list_id'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; - -export const findListItemSchema = t.intersection([ - t.exact(t.type({ list_id })), - t.exact( - t.partial({ - cursor, // defaults to undefined if not set during decode - filter, // defaults to undefined if not set during decode - page: StringToPositiveNumber, // defaults to undefined if not set during decode - per_page: StringToPositiveNumber, // defaults to undefined if not set during decode - sort_field, // defaults to undefined if not set during decode - sort_order, // defaults to undefined if not set during decode - }) - ), -]); - -export type FindListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type FindListItemSchemaDecoded = RequiredKeepUndefined>; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.mock.ts deleted file mode 100644 index 48c9671e4ac17..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.mock.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FILTER } from '../../constants/index.mock'; - -import { FindListSchema, FindListSchemaEncoded } from '.'; - -export const getFindListSchemaMock = (): FindListSchemaEncoded => ({ - filter: FILTER, - page: '1', - per_page: '25', - sort_field: undefined, - sort_order: undefined, -}); - -export const getFindListSchemaDecodedMock = (): FindListSchema => ({ - cursor: undefined, - filter: FILTER, - page: 1, - per_page: 25, - sort_field: undefined, - sort_order: undefined, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.test.ts deleted file mode 100644 index ba03ddcb85269..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getFindListSchemaDecodedMock, getFindListSchemaMock } from './index.mock'; -import { FindListSchemaEncoded, findListSchema } from '.'; - -describe('find_list_schema', () => { - test('it should validate a typical find item request', () => { - const payload = getFindListSchemaMock(); - const decoded = findListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getFindListSchemaDecodedMock()); - }); - - test('it should validate and empty object since everything is optional and will respond with an empty object', () => { - const payload: FindListSchemaEncoded = {}; - const decoded = findListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should validate with page missing', () => { - const payload = getFindListSchemaMock(); - delete payload.page; - const decoded = findListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindListSchemaDecodedMock(); - delete expected.page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with pre_page missing', () => { - const payload = getFindListSchemaMock(); - delete payload.per_page; - const decoded = findListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindListSchemaDecodedMock(); - delete expected.per_page; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with filter missing', () => { - const payload = getFindListSchemaMock(); - delete payload.filter; - const decoded = findListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindListSchemaDecodedMock(); - delete expected.filter; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_field missing', () => { - const payload = getFindListSchemaMock(); - delete payload.sort_field; - const decoded = findListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindListSchemaDecodedMock(); - delete expected.sort_field; - expect(message.schema).toEqual(expected); - }); - - test('it should validate with sort_order missing', () => { - const payload = getFindListSchemaMock(); - delete payload.sort_order; - const decoded = findListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = getFindListSchemaDecodedMock(); - delete expected.sort_order; - expect(message.schema).toEqual(expected); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: FindListSchemaEncoded & { - extraKey: string; - } = { ...getFindListSchemaMock(), extraKey: 'some new value' }; - const decoded = findListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.ts deleted file mode 100644 index 8b33ffc6a9470..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { StringToPositiveNumber } from '@kbn/securitysolution-io-ts-types'; -import { cursor } from '../../common/cursor'; -import { filter } from '../../common/filter'; -import { sort_field } from '../../common/sort_field'; -import { sort_order } from '../../common/sort_order'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; - -export const findListSchema = t.exact( - t.partial({ - cursor, // defaults to undefined if not set during decode - filter, // defaults to undefined if not set during decode - page: StringToPositiveNumber, // defaults to undefined if not set during decode - per_page: StringToPositiveNumber, // defaults to undefined if not set during decode - sort_field, // defaults to undefined if not set during decode - sort_order, // defaults to undefined if not set during decode - }) -); - -export type FindListSchema = RequiredKeepUndefined>; -export type FindListSchemaEncoded = t.OutputOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/get_exception_filter_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/get_exception_filter_schema/index.ts deleted file mode 100644 index 58c93b697a850..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/get_exception_filter_schema/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { namespaceType } from '../../common/default_namespace'; -import { exceptionListItemSchema } from '../../response'; -import { createExceptionListItemSchema } from '../create_exception_list_item_schema'; - -const exceptionListId = t.type({ - exception_list_id: t.string, - namespace_type: namespaceType, -}); - -export const exceptionListIds = t.type({ - exception_list_ids: t.array(exceptionListId), - type: t.literal('exception_list_ids'), -}); - -export const exceptions = t.type({ - exceptions: t.array(t.union([exceptionListItemSchema, createExceptionListItemSchema])), - type: t.literal('exception_items'), -}); - -const optionalExceptionParams = t.exact( - t.partial({ alias: t.string, chunk_size: t.number, exclude_exceptions: t.boolean }) -); - -export const getExceptionFilterSchema = t.intersection([ - t.union([exceptions, exceptionListIds]), - optionalExceptionParams, -]); - -export type GetExceptionFilterSchema = t.TypeOf; -export type ExceptionListId = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.mock.ts deleted file mode 100644 index e66b805de4967..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.mock.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ENTRIES } from '../../constants/index.mock'; -import { ImportExceptionListItemSchema, ImportExceptionListItemSchemaDecoded } from '.'; - -export const getImportExceptionsListItemSchemaMock = ( - itemId = 'item_id_1', - listId = 'detection_list_id' -): ImportExceptionListItemSchema => ({ - description: 'some description', - entries: ENTRIES, - item_id: itemId, - list_id: listId, - name: 'Query with a rule id', - type: 'simple', -}); - -export const getImportExceptionsListItemSchemaDecodedMock = ( - itemId = 'item_id_1', - listId = 'detection_list_id' -): ImportExceptionListItemSchemaDecoded => ({ - ...getImportExceptionsListItemSchemaMock(itemId, listId), - comments: [], - meta: undefined, - namespace_type: 'single', - os_types: [], - tags: [], - expire_time: undefined, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.test.ts deleted file mode 100644 index 58b9bce4c4108..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.test.ts +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { importExceptionListItemSchema, ImportExceptionListItemSchema } from '.'; -import { - getImportExceptionsListItemSchemaDecodedMock, - getImportExceptionsListItemSchemaMock, -} from './index.mock'; -import { getCommentsArrayMock } from '../../common/comment/index.mock'; - -describe('import_list_item_schema', () => { - test('it should validate a typical item request', () => { - const payload = getImportExceptionsListItemSchemaMock(); - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getImportExceptionsListItemSchemaDecodedMock()); - }); - - test('it should validate a typical item request with comments', () => { - const payload = { - ...getImportExceptionsListItemSchemaMock(), - comments: getCommentsArrayMock(), - }; - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual({ - ...getImportExceptionsListItemSchemaDecodedMock(), - comments: [ - { - comment: 'some old comment', - created_at: '2020-04-20T15:25:31.830Z', - created_by: 'some user', - id: 'uuid_here', - }, - { - comment: 'some old comment', - created_at: '2020-04-20T15:25:31.830Z', - created_by: 'some user', - id: 'uuid_here', - }, - ], - }); - }); - - test('it should NOT accept an undefined for "item_id"', () => { - const payload: Partial> = - getImportExceptionsListItemSchemaMock(); - delete payload.item_id; - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "item_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "list_id"', () => { - const payload: Partial> = - getImportExceptionsListItemSchemaMock(); - delete payload.list_id; - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "description"', () => { - const payload: Partial> = - getImportExceptionsListItemSchemaMock(); - delete payload.description; - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "name"', () => { - const payload: Partial> = - getImportExceptionsListItemSchemaMock(); - delete payload.name; - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "type"', () => { - const payload: Partial> = - getImportExceptionsListItemSchemaMock(); - delete payload.type; - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "entries"', () => { - const payload: Partial> = - getImportExceptionsListItemSchemaMock(); - delete payload.entries; - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept any partial fields', () => { - const payload: ImportExceptionListItemSchema = { - ...getImportExceptionsListItemSchemaMock(), - id: '123', - namespace_type: 'single', - comments: [], - os_types: [], - tags: ['123'], - created_at: '2018-08-24T17:49:30.145142000', - created_by: 'elastic', - updated_at: '2018-08-24T17:49:30.145142000', - updated_by: 'elastic', - tie_breaker_id: '123', - _version: '3', - meta: undefined, - }; - - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ImportExceptionListItemSchema & { - extraKey?: string; - } = getImportExceptionsListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = importExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.ts deleted file mode 100644 index 9b0762005f3af..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; -import { Tags } from '../../common/tags'; -import { NamespaceType } from '../../common/default_namespace'; -import { name } from '../../common/name'; -import { description } from '../../common/description'; -import { namespace_type } from '../../common/namespace_type'; -import { tags } from '../../common/tags'; -import { meta } from '../../common/meta'; -import { list_id } from '../../common/list_id'; -import { item_id } from '../../common/item_id'; -import { id } from '../../common/id'; -import { created_at } from '../../common/created_at'; -import { created_by } from '../../common/created_by'; -import { updated_at } from '../../common/updated_at'; -import { updated_by } from '../../common/updated_by'; -import { _version } from '../../common/underscore_version'; -import { tie_breaker_id } from '../../common/tie_breaker_id'; -import { nonEmptyEntriesArray } from '../../common/non_empty_entries_array'; -import { exceptionListItemType } from '../../common/exception_list_item_type'; -import { ItemId } from '../../common/item_id'; -import { EntriesArray } from '../../common/entries'; -import { DefaultImportCommentsArray } from '../../common/default_import_comments_array'; -import { ExpireTimeOrUndefined, expireTimeOrUndefined, ImportCommentsArray } from '../../common'; - -/** - * Differences from this and the createExceptionsListItemSchema are - * - item_id is required - * - id is optional (but ignored in the import code - item_id is exclusively used for imports) - * - immutable is optional but if it is any value other than false it will be rejected - * - created_at is optional (but ignored in the import code) - * - updated_at is optional (but ignored in the import code) - * - created_by is optional (but ignored in the import code) - * - updated_by is optional (but ignored in the import code) - */ -export const importExceptionListItemSchema = t.intersection([ - t.exact( - t.type({ - description, - entries: nonEmptyEntriesArray, - item_id, - list_id, - name, - type: exceptionListItemType, - }) - ), - t.exact( - t.partial({ - id, // defaults to undefined if not set during decode - comments: DefaultImportCommentsArray, // defaults to empty array if not set during decode - created_at, // defaults undefined if not set during decode - updated_at, // defaults undefined if not set during decode - created_by, // defaults undefined if not set during decode - updated_by, // defaults undefined if not set during decode - _version, // defaults to undefined if not set during decode - tie_breaker_id, - meta, // defaults to undefined if not set during decode - namespace_type, // defaults to 'single' if not set during decode - os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode - tags, // defaults to empty array if not set during decode - expire_time: expireTimeOrUndefined, - }) - ), -]); - -export type ImportExceptionListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type ImportExceptionListItemSchemaDecoded = Omit< - ImportExceptionListItemSchema, - 'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments' | 'expire_time' -> & { - comments: ImportCommentsArray; - tags: Tags; - item_id: ItemId; - entries: EntriesArray; - namespace_type: NamespaceType; - os_types: OsTypeArray; - expire_time: ExpireTimeOrUndefined; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.mock.ts deleted file mode 100644 index 5bf263beb3720..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.mock.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ImportExceptionListSchemaDecoded, ImportExceptionsListSchema } from '.'; - -export const getImportExceptionsListSchemaMock = ( - listId = 'detection_list_id' -): ImportExceptionsListSchema => ({ - description: 'some description', - list_id: listId, - name: 'Query with a rule id', - type: 'detection', -}); - -export const getImportExceptionsListSchemaDecodedMock = ( - listId = 'detection_list_id' -): ImportExceptionListSchemaDecoded => ({ - ...getImportExceptionsListSchemaMock(listId), - immutable: false, - meta: undefined, - namespace_type: 'single', - os_types: [], - tags: [], - version: 1, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.test.ts deleted file mode 100644 index 677e089fe1efe..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.test.ts +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { importExceptionsListSchema, ImportExceptionsListSchema } from '.'; -import { - getImportExceptionsListSchemaMock, - getImportExceptionsListSchemaDecodedMock, -} from './index.mock'; - -describe('import_list_item_schema', () => { - test('it should validate a typical lists request', () => { - const payload = getImportExceptionsListSchemaMock(); - const decoded = importExceptionsListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getImportExceptionsListSchemaDecodedMock()); - }); - - test('it should NOT accept an undefined for "list_id"', () => { - const payload: Partial> = - getImportExceptionsListSchemaMock(); - delete payload.list_id; - const decoded = importExceptionsListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "description"', () => { - const payload: Partial> = - getImportExceptionsListSchemaMock(); - delete payload.description; - const decoded = importExceptionsListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "name"', () => { - const payload: Partial> = - getImportExceptionsListSchemaMock(); - delete payload.name; - const decoded = importExceptionsListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "type"', () => { - const payload: Partial> = - getImportExceptionsListSchemaMock(); - delete payload.type; - const decoded = importExceptionsListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept value of "true" for "immutable"', () => { - const payload: ImportExceptionsListSchema = { - ...getImportExceptionsListSchemaMock(), - immutable: true, - }; - - const decoded = importExceptionsListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "true" supplied to "immutable"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept any partial fields', () => { - const payload: ImportExceptionsListSchema = { - ...getImportExceptionsListSchemaMock(), - namespace_type: 'single', - immutable: false, - os_types: [], - tags: ['123'], - created_at: '2018-08-24T17:49:30.145142000', - created_by: 'elastic', - updated_at: '2018-08-24T17:49:30.145142000', - updated_by: 'elastic', - version: 3, - tie_breaker_id: '123', - _version: '3', - meta: undefined, - }; - - const decoded = importExceptionsListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ImportExceptionsListSchema & { - extraKey?: string; - } = getImportExceptionsListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = importExceptionsListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.ts deleted file mode 100644 index 9c0584aa267e1..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { - DefaultVersionNumber, - DefaultVersionNumberDecoded, - OnlyFalseAllowed, -} from '@kbn/securitysolution-io-ts-types'; - -import { exceptionListType } from '../../common/exception_list'; -import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; -import { Tags } from '../../common/tags'; -import { ListId } from '../../common/list_id'; -import { NamespaceType } from '../../common/default_namespace'; -import { name } from '../../common/name'; -import { description } from '../../common/description'; -import { namespace_type } from '../../common/namespace_type'; -import { tags } from '../../common/tags'; -import { meta } from '../../common/meta'; -import { list_id } from '../../common/list_id'; -import { id } from '../../common/id'; -import { created_at } from '../../common/created_at'; -import { created_by } from '../../common/created_by'; -import { updated_at } from '../../common/updated_at'; -import { updated_by } from '../../common/updated_by'; -import { _version } from '../../common/underscore_version'; -import { tie_breaker_id } from '../../common/tie_breaker_id'; - -/** - * Differences from this and the createExceptionsSchema are - * - list_id is required - * - id is optional (but ignored in the import code - list_id is exclusively used for imports) - * - immutable is optional but if it is any value other than false it will be rejected - * - created_at is optional (but ignored in the import code) - * - updated_at is optional (but ignored in the import code) - * - created_by is optional (but ignored in the import code) - * - updated_by is optional (but ignored in the import code) - */ -export const importExceptionsListSchema = t.intersection([ - t.exact( - t.type({ - description, - name, - type: exceptionListType, - list_id, - }) - ), - t.exact( - t.partial({ - id, // defaults to undefined if not set during decode - immutable: OnlyFalseAllowed, - meta, // defaults to undefined if not set during decode - namespace_type, // defaults to 'single' if not set during decode - os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode - tags, // defaults to empty array if not set during decode - created_at, // defaults "undefined" if not set during decode - updated_at, // defaults "undefined" if not set during decode - created_by, // defaults "undefined" if not set during decode - updated_by, // defaults "undefined" if not set during decode - _version, // defaults to undefined if not set during decode - tie_breaker_id, - version: DefaultVersionNumber, // defaults to numerical 1 if not set during decode - }) - ), -]); - -export type ImportExceptionsListSchema = t.TypeOf; - -// This type is used after a decode since some things are defaults after a decode. -export type ImportExceptionListSchemaDecoded = Omit< - ImportExceptionsListSchema, - 'tags' | 'list_id' | 'namespace_type' | 'os_types' | 'immutable' -> & { - immutable: false; - tags: Tags; - list_id: ListId; - namespace_type: NamespaceType; - os_types: OsTypeArray; - version: DefaultVersionNumberDecoded; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.mock.ts deleted file mode 100644 index 74a2122ff1dc4..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.mock.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { LIST_ID, TYPE } from '../../constants/index.mock'; - -import { ImportListItemQuerySchema } from '.'; - -export const getImportListItemQuerySchemaMock = (): ImportListItemQuerySchema => ({ - deserializer: undefined, - list_id: LIST_ID, - serializer: undefined, - type: TYPE, - refresh: 'false', -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.test.ts deleted file mode 100644 index b0ec4f10af876..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { ImportListItemQuerySchema, importListItemQuerySchema } from '.'; -import { getImportListItemQuerySchemaMock } from './index.mock'; - -describe('import_list_item_schema', () => { - test('it should validate a typical lists request', () => { - const payload = getImportListItemQuerySchemaMock(); - const decoded = importListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "list_id"', () => { - const payload = getImportListItemQuerySchemaMock(); - delete payload.list_id; - const decoded = importListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "type"', () => { - const payload = getImportListItemQuerySchemaMock(); - delete payload.type; - const decoded = importListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "type" and "list_id', () => { - const payload = getImportListItemQuerySchemaMock(); - delete payload.type; - delete payload.list_id; - const decoded = importListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "serializer"', () => { - const payload = getImportListItemQuerySchemaMock(); - delete payload.serializer; - const decoded = importListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "deserializer"', () => { - const payload = getImportListItemQuerySchemaMock(); - delete payload.deserializer; - const decoded = importListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ImportListItemQuerySchema & { - extraKey?: string; - } = getImportListItemQuerySchemaMock(); - payload.extraKey = 'some new value'; - const decoded = importListItemQuerySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.ts deleted file mode 100644 index e34d94c498662..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { deserializer } from '../../common/deserializer'; -import { list_id } from '../../common/list_id'; -import { type } from '../../common/type'; -import { serializer } from '../../common/serializer'; -import { refreshWithWaitFor } from '../../common/refresh'; - -export const importListItemQuerySchema = t.exact( - t.partial({ deserializer, list_id, serializer, type, refresh: refreshWithWaitFor }) -); - -export type ImportListItemQuerySchema = RequiredKeepUndefined< - t.TypeOf ->; -export type ImportListItemQuerySchemaEncoded = t.OutputOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.mock.ts deleted file mode 100644 index 15dd19d4bdefd..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.mock.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ImportListItemSchema } from '.'; - -export const getImportListItemSchemaMock = (): ImportListItemSchema => ({ - file: {}, -}); - -/** - * This is useful for end to end tests, it will return a buffer given a string array - * of things to import. - * @param input Array of strings of things to import - */ -export const getImportListItemAsBuffer = (input: string[]): Buffer => { - return Buffer.from(input.join('\r\n')); -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.test.ts deleted file mode 100644 index c4841f394f8d1..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { ImportListItemSchema, importListItemSchema } from '.'; -import { getImportListItemSchemaMock } from './index.mock'; - -describe('import_list_item_schema', () => { - test('it should validate a typical lists request', () => { - const payload = getImportListItemSchemaMock(); - const decoded = importListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for a file', () => { - const payload = getImportListItemSchemaMock(); - // @ts-expect-error - delete payload.file; - const decoded = importListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "file"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ImportListItemSchema & { - extraKey?: string; - } = getImportListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = importListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.ts deleted file mode 100644 index 45dbf838e5871..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { file } from '../../common/file'; - -export const importListItemSchema = t.exact( - t.type({ - file, - }) -); - -export type ImportListItemSchema = RequiredKeepUndefined>; -export type ImportListItemSchemaEncoded = t.OutputOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts deleted file mode 100644 index 3d21a5ffdcb24..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './create_endpoint_list_item_schema'; -export * from './create_exception_list_item_schema'; -export * from './create_exception_list_schema'; -export * from './create_rule_exception_item_schema'; -export * from './create_list_item_schema'; -export * from './create_list_schema'; -export * from './delete_endpoint_list_item_schema'; -export * from './delete_exception_list_schema'; -export * from './delete_exception_list_item_schema'; -export * from './delete_list_item_schema'; -export * from './delete_list_schema'; -export * from './duplicate_exception_list_query_schema'; -export * from './export_exception_list_query_schema'; -export * from './export_list_item_query_schema'; -export * from './find_endpoint_list_item_schema'; -export * from './find_exception_list_schema'; -export * from './find_exception_list_item_schema'; -export * from './find_list_item_schema'; -export * from './find_list_schema'; -export * from './get_exception_filter_schema'; -export * from './import_list_item_query_schema'; -export * from './import_exception_list_schema'; -export * from './import_exception_item_schema'; -export * from './import_list_item_schema'; -export * from './patch_list_item_schema'; -export * from './patch_list_schema'; -export * from './read_endpoint_list_item_schema'; -export * from './read_exception_list_item_schema'; -export * from './read_exception_list_schema'; -export * from './read_list_item_schema'; -export * from './read_list_schema'; -export * from './summary_exception_list_schema'; -export * from './update_endpoint_list_item_schema'; -export * from './update_exception_list_item_schema'; -export * from './update_exception_list_schema'; -export * from './update_list_item_schema'; -export * from './update_list_schema'; - -// Internal routes -export * from './internal/create_exception_list_schema'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.test.ts deleted file mode 100644 index 4a4a090723c39..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; - -import { ExceptionListTypeEnum } from '../../../common/exception_list'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { internalCreateExceptionListSchema } from '.'; -import { getCreateExceptionListSchemaMock } from '../../create_exception_list_schema/index.mock'; - -describe('create_exception_list_schema', () => { - test('it should accept artifact list_id', () => { - const payload = { - ...getCreateExceptionListSchemaMock(), - list_id: ExceptionListTypeEnum.ENDPOINT_BLOCKLISTS, - }; - const decoded = internalCreateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - test('it should fail when invalid list_id', () => { - const payload = { - ...getCreateExceptionListSchemaMock(), - list_id: ExceptionListTypeEnum.DETECTION, - }; - const decoded = internalCreateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "detection" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - test('it should accept artifact type', () => { - const payload = { - ...getCreateExceptionListSchemaMock(), - list_id: ExceptionListTypeEnum.ENDPOINT_BLOCKLISTS, - type: ExceptionListTypeEnum.ENDPOINT_BLOCKLISTS, - }; - const decoded = internalCreateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - test('it should fail when invalid type', () => { - const payload = { - ...getCreateExceptionListSchemaMock(), - list_id: ExceptionListTypeEnum.ENDPOINT_BLOCKLISTS, - type: ExceptionListTypeEnum.DETECTION, - }; - const decoded = internalCreateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "detection" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.ts deleted file mode 100644 index 3aa11ba500502..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ENDPOINT_ARTIFACT_LIST_IDS } from '@kbn/securitysolution-list-constants'; -import * as t from 'io-ts'; - -import { - createExceptionListSchema, - CreateExceptionListSchemaDecoded, -} from '../../create_exception_list_schema'; - -export const internalCreateExceptionListSchema = t.intersection([ - t.exact( - t.type({ - type: t.keyof({ - endpoint: null, - endpoint_events: null, - endpoint_host_isolation_exceptions: null, - endpoint_blocklists: null, - }), - }) - ), - t.exact( - t.partial({ - list_id: t.keyof( - ENDPOINT_ARTIFACT_LIST_IDS.reduce>((mapOfListIds, listId) => { - mapOfListIds[listId] = null; - - return mapOfListIds; - }, {}) - ), - }) - ), - createExceptionListSchema, -]); - -export type InternalCreateExceptionListSchema = t.OutputOf< - typeof internalCreateExceptionListSchema ->; - -// This type is used after a decode since some things are defaults after a decode. -export type InternalCreateExceptionListSchemaDecoded = CreateExceptionListSchemaDecoded; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.mock.ts deleted file mode 100644 index ff156386baa93..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { LIST_ITEM_ID, META, VALUE } from '../../constants/index.mock'; - -import { PatchListItemSchema } from '.'; - -export const getPathListItemSchemaMock = (): PatchListItemSchema => ({ - id: LIST_ITEM_ID, - meta: META, - value: VALUE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.test.ts deleted file mode 100644 index fddeeaf0055c5..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getPathListItemSchemaMock } from './index.mock'; -import { PatchListItemSchema, patchListItemSchema } from '.'; - -describe('patch_list_item_schema', () => { - test('it should validate a typical list item request', () => { - const payload = getPathListItemSchemaMock(); - const decoded = patchListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "id"', () => { - const payload = getPathListItemSchemaMock(); - // @ts-expect-error - delete payload.id; - const decoded = patchListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "meta"', () => { - const payload = getPathListItemSchemaMock(); - delete payload.meta; - const decoded = patchListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "value"', () => { - const payload = getPathListItemSchemaMock(); - delete payload.value; - const decoded = patchListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "meta" and "value"', () => { - const payload = getPathListItemSchemaMock(); - delete payload.meta; - delete payload.value; - const decoded = patchListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: PatchListItemSchema & { extraKey?: string } = getPathListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = patchListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.ts deleted file mode 100644 index 96b50702d99b2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { _version } from '../../common/underscore_version'; -import { id } from '../../common/id'; -import { meta } from '../../common/meta'; -import { value } from '../../common/value'; -import { refresh } from '../../common/refresh'; - -export const patchListItemSchema = t.intersection([ - t.exact( - t.type({ - id, - }) - ), - t.exact(t.partial({ _version, meta, value, refresh })), -]); - -export type PatchListItemSchema = t.OutputOf; -export type PatchListItemSchemaDecoded = RequiredKeepUndefined< - t.TypeOf ->; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.mock.ts deleted file mode 100644 index 818dd4e79e98f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.mock.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DESCRIPTION, LIST_ITEM_ID, META, NAME } from '../../constants/index.mock'; - -import { PatchListSchema } from '.'; - -export const getPathListSchemaMock = (): PatchListSchema => ({ - description: DESCRIPTION, - id: LIST_ITEM_ID, - meta: META, - name: NAME, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.test.ts deleted file mode 100644 index b79bfc8fddd65..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.test.ts +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getPathListSchemaMock } from './index.mock'; -import { PatchListSchema, patchListSchema } from '.'; - -describe('patch_list_schema', () => { - test('it should validate a typical list item request', () => { - const payload = getPathListSchemaMock(); - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "id"', () => { - const payload = getPathListSchemaMock(); - // @ts-expect-error - delete payload.id; - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "meta"', () => { - const payload = getPathListSchemaMock(); - delete payload.meta; - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "name"', () => { - const payload = getPathListSchemaMock(); - delete payload.name; - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "description"', () => { - const payload = getPathListSchemaMock(); - delete payload.description; - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "description", "meta", "name', () => { - const payload = getPathListSchemaMock(); - delete payload.description; - delete payload.name; - delete payload.meta; - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "description", "meta"', () => { - const payload = getPathListSchemaMock(); - delete payload.description; - delete payload.meta; - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "description", "name"', () => { - const payload = getPathListSchemaMock(); - delete payload.description; - delete payload.name; - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "meta", "name"', () => { - const payload = getPathListSchemaMock(); - delete payload.meta; - delete payload.name; - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: PatchListSchema & { extraKey?: string } = getPathListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = patchListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.ts deleted file mode 100644 index e5c477c844247..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { version } from '@kbn/securitysolution-io-ts-types'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { _version } from '../../common/underscore_version'; -import { meta } from '../../common/meta'; -import { name } from '../../common/name'; -import { description } from '../../common/description'; - -export const patchListSchema = t.intersection([ - t.exact( - t.type({ - id, - }) - ), - t.exact( - t.partial({ - _version, // is undefined if not set during decode - description, // is undefined if not set during decode - meta, // is undefined if not set during decode - name, // is undefined if not set during decode - version, // is undefined if not set during decode - }) - ), -]); - -export type PatchListSchema = t.OutputOf; -export type PatchListSchemaDecoded = RequiredKeepUndefined>; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.mock.ts deleted file mode 100644 index d7850f0cca32e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.mock.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ID, ITEM_ID } from '../../constants/index.mock'; - -import { ReadEndpointListItemSchema } from '.'; - -export const getReadEndpointListItemSchemaMock = (): ReadEndpointListItemSchema => ({ - id: ID, - item_id: ITEM_ID, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.test.ts deleted file mode 100644 index d9de257a31300..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getReadEndpointListItemSchemaMock } from './index.mock'; -import { ReadEndpointListItemSchema, readEndpointListItemSchema } from '.'; - -describe('read_endpoint_list_item_schema', () => { - test('it should validate a typical list request', () => { - const payload = getReadEndpointListItemSchemaMock(); - const decoded = readEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id"', () => { - const payload = getReadEndpointListItemSchemaMock(); - delete payload.id; - const decoded = readEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "item_id"', () => { - const payload = getReadEndpointListItemSchemaMock(); - delete payload.item_id; - const decoded = readEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept "namespace_type" since endpoint list items do not need it', () => { - const payload: ReadEndpointListItemSchema & { - namespace_type: string; - } = { ...getReadEndpointListItemSchemaMock(), namespace_type: 'single' }; - // @ts-expect-error - delete payload.namespace_type; - const decoded = readEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getReadEndpointListItemSchemaMock()); - }); - - test('it should accept an undefined for "id", "item_id"', () => { - const payload = getReadEndpointListItemSchemaMock(); - delete payload.id; - delete payload.item_id; - const decoded = readEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ReadEndpointListItemSchema & { - extraKey?: string; - } = getReadEndpointListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = readEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.ts deleted file mode 100644 index dbf3a59d79b3a..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { item_id } from '../../common/item_id'; - -export const readEndpointListItemSchema = t.exact( - t.partial({ - id, - item_id, - }) -); - -export type ReadEndpointListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type ReadEndpointListItemSchemaDecoded = RequiredKeepUndefined< - t.TypeOf ->; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.mock.ts deleted file mode 100644 index 00e72dc68f5fc..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ID, ITEM_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { ReadExceptionListItemSchema } from '.'; - -export const getReadExceptionListItemSchemaMock = (): ReadExceptionListItemSchema => ({ - id: ID, - item_id: ITEM_ID, - namespace_type: NAMESPACE_TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.test.ts deleted file mode 100644 index e1c4615510305..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getReadExceptionListItemSchemaMock } from './index.mock'; -import { ReadExceptionListItemSchema, readExceptionListItemSchema } from '.'; - -describe('read_exception_list_item_schema', () => { - test('it should validate a typical exception list request', () => { - const payload = getReadExceptionListItemSchemaMock(); - const decoded = readExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id"', () => { - const payload = getReadExceptionListItemSchemaMock(); - delete payload.id; - const decoded = readExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "item_id"', () => { - const payload = getReadExceptionListItemSchemaMock(); - delete payload.item_id; - const decoded = readExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "namespace_type" but default to "single"', () => { - const payload = getReadExceptionListItemSchemaMock(); - delete payload.namespace_type; - const decoded = readExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getReadExceptionListItemSchemaMock()); - }); - - test('it should accept an undefined for "id", "item_id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getReadExceptionListItemSchemaMock(); - delete payload.id; - delete payload.namespace_type; - delete payload.item_id; - const output = getReadExceptionListItemSchemaMock(); - delete output.id; - delete output.item_id; - const decoded = readExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should accept an undefined for "id", "item_id"', () => { - const payload = getReadExceptionListItemSchemaMock(); - delete payload.id; - delete payload.item_id; - const decoded = readExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getReadExceptionListItemSchemaMock(); - delete payload.id; - delete payload.namespace_type; - const output = getReadExceptionListItemSchemaMock(); - delete output.id; - const decoded = readExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should accept an undefined for "item_id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getReadExceptionListItemSchemaMock(); - delete payload.namespace_type; - delete payload.item_id; - const output = getReadExceptionListItemSchemaMock(); - delete output.item_id; - const decoded = readExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ReadExceptionListItemSchema & { - extraKey?: string; - } = getReadExceptionListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = readExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.ts deleted file mode 100644 index 6f54ede5ff51d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { NamespaceType } from '../../common/default_namespace'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { item_id } from '../../common/item_id'; -import { namespace_type } from '../../common/namespace_type'; - -export const readExceptionListItemSchema = t.exact( - t.partial({ - id, - item_id, - namespace_type, // defaults to 'single' if not set during decode - }) -); - -export type ReadExceptionListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type ReadExceptionListItemSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'namespace_type' -> & { - namespace_type: NamespaceType; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.mock.ts deleted file mode 100644 index 47fcba01fd95e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ID, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { ReadExceptionListSchema } from '.'; - -export const getReadExceptionListSchemaMock = (): ReadExceptionListSchema => ({ - id: ID, - list_id: LIST_ID, - namespace_type: NAMESPACE_TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.test.ts deleted file mode 100644 index 2c5a93021b7ca..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getReadExceptionListSchemaMock } from './index.mock'; -import { ReadExceptionListSchema, readExceptionListSchema } from '.'; - -describe('read_exception_list_schema', () => { - test('it should validate a typical exception list request', () => { - const payload = getReadExceptionListSchemaMock(); - const decoded = readExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id"', () => { - const payload = getReadExceptionListSchemaMock(); - delete payload.id; - const decoded = readExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "list_id"', () => { - const payload = getReadExceptionListSchemaMock(); - delete payload.list_id; - const decoded = readExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "namespace_type" but default to "single"', () => { - const payload = getReadExceptionListSchemaMock(); - delete payload.namespace_type; - const decoded = readExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getReadExceptionListSchemaMock()); - }); - - test('it should accept an undefined for "id", "list_id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getReadExceptionListSchemaMock(); - delete payload.id; - delete payload.namespace_type; - delete payload.list_id; - const output = getReadExceptionListSchemaMock(); - delete output.id; - delete output.list_id; - const decoded = readExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should accept an undefined for "id", "list_id"', () => { - const payload = getReadExceptionListSchemaMock(); - delete payload.id; - delete payload.list_id; - const decoded = readExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getReadExceptionListSchemaMock(); - delete payload.id; - delete payload.namespace_type; - const output = getReadExceptionListSchemaMock(); - delete output.id; - const decoded = readExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should accept an undefined for "list_id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getReadExceptionListSchemaMock(); - delete payload.namespace_type; - delete payload.list_id; - const output = getReadExceptionListSchemaMock(); - delete output.list_id; - const decoded = readExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ReadExceptionListSchema & { - extraKey?: string; - } = getReadExceptionListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = readExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.ts deleted file mode 100644 index fb2e66d2f1de2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { NamespaceType } from '../../common/default_namespace'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { list_id } from '../../common/list_id'; -import { namespace_type } from '../../common/namespace_type'; - -export const readExceptionListSchema = t.exact( - t.partial({ - id, - list_id, - namespace_type, // defaults to 'single' if not set during decode - }) -); - -export type ReadExceptionListSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type ReadExceptionListSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'namespace_type' -> & { - namespace_type: NamespaceType; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.mock.ts deleted file mode 100644 index d78bb6f44bc78..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { LIST_ID, LIST_ITEM_ID, VALUE } from '../../constants/index.mock'; - -import { ReadListItemSchema } from '.'; - -export const getReadListItemSchemaMock = (): ReadListItemSchema => ({ - id: LIST_ITEM_ID, - list_id: LIST_ID, - value: VALUE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.test.ts deleted file mode 100644 index 547537afc6735..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getReadListItemSchemaMock } from './index.mock'; -import { ReadListItemSchema, readListItemSchema } from '.'; - -describe('read_list_item_schema', () => { - test('it should validate a typical list item request', () => { - const payload = getReadListItemSchemaMock(); - const decoded = readListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id"', () => { - const payload = getReadListItemSchemaMock(); - delete payload.id; - const decoded = readListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "list_id"', () => { - const payload = getReadListItemSchemaMock(); - delete payload.list_id; - const decoded = readListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "value"', () => { - const payload = getReadListItemSchemaMock(); - delete payload.value; - const decoded = readListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id", "list_id", "value"', () => { - const payload = getReadListItemSchemaMock(); - delete payload.id; - delete payload.value; - delete payload.list_id; - const decoded = readListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id", "list_id"', () => { - const payload = getReadListItemSchemaMock(); - delete payload.id; - delete payload.list_id; - const decoded = readListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id", "value"', () => { - const payload = getReadListItemSchemaMock(); - delete payload.id; - delete payload.value; - const decoded = readListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "list_id", "value"', () => { - const payload = getReadListItemSchemaMock(); - delete payload.value; - delete payload.list_id; - const decoded = readListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ReadListItemSchema & { extraKey?: string } = getReadListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = readListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.ts deleted file mode 100644 index 3b45ebeea6bae..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { list_id } from '../../common/list_id'; -import { value } from '../../common/value'; - -export const readListItemSchema = t.exact(t.partial({ id, list_id, value })); - -export type ReadListItemSchema = t.OutputOf; -export type ReadListItemSchemaDecoded = RequiredKeepUndefined>; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.mock.ts deleted file mode 100644 index 5eecbd49e472a..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.mock.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { LIST_ID } from '../../constants/index.mock'; - -import { ReadListSchema } from '.'; - -export const getReadListSchemaMock = (): ReadListSchema => ({ - id: LIST_ID, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.test.ts deleted file mode 100644 index d26f8206c4985..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getReadListSchemaMock } from './index.mock'; -import { ReadListSchema, readListSchema } from '.'; - -describe('read_list_schema', () => { - test('it should validate a typical list item request', () => { - const payload = getReadListSchemaMock(); - const decoded = readListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "id"', () => { - const payload = getReadListSchemaMock(); - // @ts-expect-error - delete payload.id; - const decoded = readListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ReadListSchema & { extraKey?: string } = getReadListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = readListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.ts deleted file mode 100644 index b9c008287139e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { id } from '../../common/id'; - -export const readListSchema = t.exact( - t.type({ - id, - }) -); - -export type ReadListSchema = t.OutputOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts deleted file mode 100644 index 61e8dfbae15fd..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FILTER, ID, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { SummaryExceptionListSchema } from '.'; - -export const getSummaryExceptionListSchemaMock = (): SummaryExceptionListSchema => ({ - filter: FILTER, - id: ID, - list_id: LIST_ID, - namespace_type: NAMESPACE_TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts deleted file mode 100644 index 06db32fa2df30..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getSummaryExceptionListSchemaMock } from './index.mock'; -import { SummaryExceptionListSchema, summaryExceptionListSchema } from '.'; - -describe('summary_exception_list_schema', () => { - test('it should validate a typical exception list request', () => { - const payload = getSummaryExceptionListSchemaMock(); - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "filter"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.filter; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "list_id"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.list_id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "namespace_type" but default to "single"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.namespace_type; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(getSummaryExceptionListSchemaMock()); - }); - - test('it should accept an undefined for "id", "list_id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.id; - delete payload.namespace_type; - delete payload.list_id; - const output = getSummaryExceptionListSchemaMock(); - delete output.id; - delete output.list_id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should accept an undefined for "id", "list_id"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.id; - delete payload.list_id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.id; - delete payload.namespace_type; - const output = getSummaryExceptionListSchemaMock(); - delete output.id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should accept an undefined for "list_id", "namespace_type" but default "namespace_type" to "single"', () => { - const payload = getSummaryExceptionListSchemaMock(); - delete payload.namespace_type; - delete payload.list_id; - const output = getSummaryExceptionListSchemaMock(); - delete output.list_id; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(output); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: SummaryExceptionListSchema & { - extraKey?: string; - } = getSummaryExceptionListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = summaryExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = foldLeftRight(checked); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts deleted file mode 100644 index 2815dfa05b27e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { NamespaceType } from '../../common/default_namespace'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { filter, Filter } from '../../common/filter'; -import { list_id } from '../../common/list_id'; -import { namespace_type } from '../../common/namespace_type'; - -export const summaryExceptionListSchema = t.exact( - t.partial({ - filter, - id, - list_id, - namespace_type, // defaults to 'single' if not set during decode - }) -); - -export type SummaryExceptionListSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type SummaryExceptionListSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'namespace_type' -> & { - namespace_type: NamespaceType; - filter: Filter; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.mock.ts deleted file mode 100644 index 8b34549a8c90f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.mock.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - COMMENTS, - DESCRIPTION, - ENTRIES, - ID, - ITEM_TYPE, - LIST_ITEM_ID, - META, - NAME, - OS_TYPES, - TAGS, -} from '../../constants/index.mock'; - -import { UpdateEndpointListItemSchema } from '.'; - -export const getUpdateEndpointListItemSchemaMock = (): UpdateEndpointListItemSchema => ({ - _version: undefined, - comments: COMMENTS, - description: DESCRIPTION, - entries: ENTRIES, - id: ID, - item_id: LIST_ITEM_ID, - meta: META, - name: NAME, - os_types: OS_TYPES, - tags: TAGS, - type: ITEM_TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.test.ts deleted file mode 100644 index f595ecd1ebbed..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { UpdateEndpointListItemSchema, updateEndpointListItemSchema } from '.'; -import { getUpdateEndpointListItemSchemaMock } from './index.mock'; - -describe('update_endpoint_list_item_schema', () => { - test('it should validate a typical list item request', () => { - const payload = getUpdateEndpointListItemSchemaMock(); - const decoded = updateEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not accept an undefined for "description"', () => { - const payload = getUpdateEndpointListItemSchemaMock(); - // @ts-expect-error - delete payload.description; - const decoded = updateEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not accept an undefined for "name"', () => { - const payload = getUpdateEndpointListItemSchemaMock(); - // @ts-expect-error - delete payload.name; - const decoded = updateEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not accept an undefined for "type"', () => { - const payload = getUpdateEndpointListItemSchemaMock(); - // @ts-expect-error - delete payload.type; - const decoded = updateEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not accept a value for "list_id"', () => { - const payload: UpdateEndpointListItemSchema & { - list_id?: string; - } = getUpdateEndpointListItemSchemaMock(); - payload.list_id = 'some new list_id'; - const decoded = updateEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "list_id"']); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "meta" but strip it out', () => { - const payload = getUpdateEndpointListItemSchemaMock(); - const outputPayload = getUpdateEndpointListItemSchemaMock(); - delete payload.meta; - const decoded = updateEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete outputPayload.meta; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should accept an undefined for "comments" but return an array', () => { - const inputPayload = getUpdateEndpointListItemSchemaMock(); - const outputPayload = getUpdateEndpointListItemSchemaMock(); - delete inputPayload.comments; - outputPayload.comments = []; - const decoded = updateEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should NOT accept an undefined for "entries"', () => { - const inputPayload = getUpdateEndpointListItemSchemaMock(); - const outputPayload = getUpdateEndpointListItemSchemaMock(); - // @ts-expect-error - delete inputPayload.entries; - outputPayload.entries = []; - const decoded = updateEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "tags" but return an array', () => { - const inputPayload = getUpdateEndpointListItemSchemaMock(); - const outputPayload = getUpdateEndpointListItemSchemaMock(); - delete inputPayload.tags; - outputPayload.tags = []; - const decoded = updateEndpointListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: UpdateEndpointListItemSchema & { - extraKey?: string; - } = getUpdateEndpointListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = updateEndpointListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.ts deleted file mode 100644 index 7851d80ef2ef9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { DefaultUpdateCommentsArray } from '../../common/default_update_comments_array'; -import { exceptionListItemType } from '../../common/exception_list_item_type'; -import { nonEmptyEntriesArray } from '../../common/non_empty_entries_array'; -import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; -import { description } from '../../common/description'; -import { name } from '../../common/name'; -import { _version } from '../../common/underscore_version'; -import { id } from '../../common/id'; -import { meta } from '../../common/meta'; -import { Tags, tags } from '../../common/tags'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { UpdateCommentsArray } from '../../common/update_comment'; -import { EntriesArray } from '../../common/entries'; - -export const updateEndpointListItemSchema = t.intersection([ - t.exact( - t.type({ - description, - entries: nonEmptyEntriesArray, - name, - type: exceptionListItemType, - }) - ), - t.exact( - t.partial({ - _version, // defaults to undefined if not set during decode - comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode - id, // defaults to undefined if not set during decode - item_id: t.union([t.string, t.undefined]), - meta, // defaults to undefined if not set during decode - os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode - tags, // defaults to empty array if not set during decode - }) - ), -]); - -export type UpdateEndpointListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type UpdateEndpointListItemSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'tags' | 'entries' | 'comments' -> & { - comments: UpdateCommentsArray; - tags: Tags; - entries: EntriesArray; - os_types: OsTypeArray; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.mock.ts deleted file mode 100644 index fce5d2f7e18bc..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.mock.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - COMMENTS, - DESCRIPTION, - ENTRIES, - ID, - ITEM_ID, - ITEM_TYPE, - LIST_ITEM_ID, - META, - NAME, - NAMESPACE_TYPE, - OS_TYPES, - TAGS, -} from '../../constants/index.mock'; - -import { UpdateExceptionListItemSchema } from '.'; - -export const getUpdateExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({ - _version: undefined, - comments: COMMENTS, - description: DESCRIPTION, - entries: ENTRIES, - id: ID, - item_id: LIST_ITEM_ID, - meta: META, - name: NAME, - namespace_type: NAMESPACE_TYPE, - os_types: ['linux'], - tags: TAGS, - type: ITEM_TYPE, -}); - -/** - * Useful for end to end tests and other mechanisms which want to fill in the values - * after doing a get of the structure. - */ -export const getUpdateMinimalExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({ - description: DESCRIPTION, - entries: ENTRIES, - item_id: ITEM_ID, - name: NAME, - os_types: OS_TYPES, - type: ITEM_TYPE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.test.ts deleted file mode 100644 index 84e9b801c171d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.test.ts +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { UpdateExceptionListItemSchema, updateExceptionListItemSchema } from '.'; -import { getUpdateExceptionListItemSchemaMock } from './index.mock'; - -describe('update_exception_list_item_schema', () => { - test('it should validate a typical exception list item request', () => { - const payload = getUpdateExceptionListItemSchemaMock(); - const decoded = updateExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not accept an undefined for "description"', () => { - const payload = getUpdateExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.description; - const decoded = updateExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not accept an undefined for "name"', () => { - const payload = getUpdateExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.name; - const decoded = updateExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not accept an undefined for "type"', () => { - const payload = getUpdateExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.type; - const decoded = updateExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not accept a value for "list_id"', () => { - const payload: UpdateExceptionListItemSchema & { - list_id?: string; - } = getUpdateExceptionListItemSchemaMock(); - payload.list_id = 'some new list_id'; - const decoded = updateExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "list_id"']); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "meta" but strip it out', () => { - const payload = getUpdateExceptionListItemSchemaMock(); - const outputPayload = getUpdateExceptionListItemSchemaMock(); - delete payload.meta; - const decoded = updateExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete outputPayload.meta; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should accept an undefined for "comments" but return an array', () => { - const inputPayload = getUpdateExceptionListItemSchemaMock(); - const outputPayload = getUpdateExceptionListItemSchemaMock(); - delete inputPayload.comments; - outputPayload.comments = []; - const decoded = updateExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should NOT accept an undefined for "entries"', () => { - const inputPayload = getUpdateExceptionListItemSchemaMock(); - const outputPayload = getUpdateExceptionListItemSchemaMock(); - // @ts-expect-error - delete inputPayload.entries; - outputPayload.entries = []; - const decoded = updateExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "namespace_type" but return enum "single"', () => { - const inputPayload = getUpdateExceptionListItemSchemaMock(); - const outputPayload = getUpdateExceptionListItemSchemaMock(); - delete inputPayload.namespace_type; - outputPayload.namespace_type = 'single'; - const decoded = updateExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should accept an undefined for "tags" but return an array', () => { - const inputPayload = getUpdateExceptionListItemSchemaMock(); - const outputPayload = getUpdateExceptionListItemSchemaMock(); - delete inputPayload.tags; - outputPayload.tags = []; - const decoded = updateExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should accept an undefined for "item_id" and generate a correct body not counting the uuid', () => { - const inputPayload = getUpdateExceptionListItemSchemaMock(); - delete inputPayload.item_id; - const decoded = updateExceptionListItemSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as UpdateExceptionListItemSchema).item_id; - expect(message.schema).toEqual(inputPayload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: UpdateExceptionListItemSchema & { - extraKey?: string; - } = getUpdateExceptionListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = updateExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.ts deleted file mode 100644 index b0190d8fa3883..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { ExceptionListItemEntryArray } from '@kbn/securitysolution-exceptions-common/api'; -import { NamespaceType } from '../../common/default_namespace'; -import { DefaultUpdateCommentsArray } from '../../common/default_update_comments_array'; -import { exceptionListItemType } from '../../common/exception_list_item_type'; -import { nonEmptyEntriesArray } from '../../common/non_empty_entries_array'; -import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { Tags, tags } from '../../common/tags'; -import { UpdateCommentsArray } from '../../common/update_comment'; -import { description } from '../../common/description'; -import { name } from '../../common/name'; -import { _version } from '../../common/underscore_version'; -import { id } from '../../common/id'; -import { item_id } from '../../common/item_id'; -import { meta } from '../../common/meta'; -import { namespace_type } from '../../common/namespace_type'; -import { ExpireTimeOrUndefined, expireTimeOrUndefined } from '../../common'; - -export const updateExceptionListItemSchema = t.intersection([ - t.exact( - t.type({ - description, - entries: nonEmptyEntriesArray, - name, - type: exceptionListItemType, - }) - ), - t.exact( - t.partial({ - _version, // defaults to undefined if not set during decode - comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode - expire_time: expireTimeOrUndefined, - id, // defaults to undefined if not set during decode - item_id, - meta, // defaults to undefined if not set during decode - namespace_type, // defaults to 'single' if not set during decode - os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode - tags, // defaults to empty array if not set during decode - }) - ), -]); - -export type UpdateExceptionListItemSchema = t.OutputOf; - -// This type is used after a decode since some things are defaults after a decode. -export type UpdateExceptionListItemSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'tags' | 'entries' | 'namespace_type' | 'comments' | 'os_types' | 'expire_time' -> & { - comments: UpdateCommentsArray; - tags: Tags; - entries: ExceptionListItemEntryArray; - namespace_type: NamespaceType; - os_types: OsTypeArray; - expire_time: ExpireTimeOrUndefined; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.mock.ts deleted file mode 100644 index ff98cc71f03f4..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.mock.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DESCRIPTION, ID, LIST_ID, META, NAME, NAMESPACE_TYPE } from '../../constants/index.mock'; - -import { UpdateExceptionListSchema } from '.'; - -export const getUpdateExceptionListSchemaMock = (): UpdateExceptionListSchema => ({ - _version: undefined, - description: DESCRIPTION, - id: ID, - list_id: LIST_ID, - meta: META, - name: NAME, - namespace_type: NAMESPACE_TYPE, - os_types: [], - tags: ['malware'], - type: 'endpoint', -}); - -/** - * Useful for end to end tests and other mechanisms which want to fill in the values - * after doing a get of the structure. - */ -export const getUpdateMinimalExceptionListSchemaMock = (): UpdateExceptionListSchema => ({ - description: DESCRIPTION, - list_id: LIST_ID, - name: NAME, - type: 'endpoint', -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.test.ts deleted file mode 100644 index 4821251f36d14..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.test.ts +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { UpdateExceptionListSchema, updateExceptionListSchema } from '.'; -import { getUpdateExceptionListSchemaMock } from './index.mock'; - -describe('update_exception_list_schema', () => { - test('it should validate a typical exception list request', () => { - const payload = getUpdateExceptionListSchemaMock(); - const decoded = updateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not accept an undefined for "description"', () => { - const payload = getUpdateExceptionListSchemaMock(); - // @ts-expect-error - delete payload.description; - const decoded = updateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not accept an undefined for "name"', () => { - const payload = getUpdateExceptionListSchemaMock(); - // @ts-expect-error - delete payload.name; - const decoded = updateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not accept an undefined for "type"', () => { - const payload = getUpdateExceptionListSchemaMock(); - // @ts-expect-error - delete payload.type; - const decoded = updateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "meta" but strip it out', () => { - const payload = getUpdateExceptionListSchemaMock(); - const outputPayload = getUpdateExceptionListSchemaMock(); - delete payload.meta; - const decoded = updateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete outputPayload.meta; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should accept an undefined for "namespace_type" but return enum "single"', () => { - const inputPayload = getUpdateExceptionListSchemaMock(); - const outputPayload = getUpdateExceptionListSchemaMock(); - delete inputPayload.namespace_type; - outputPayload.namespace_type = 'single'; - const decoded = updateExceptionListSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should accept an undefined for "tags" but return an array', () => { - const inputPayload = getUpdateExceptionListSchemaMock(); - const outputPayload = getUpdateExceptionListSchemaMock(); - delete inputPayload.tags; - outputPayload.tags = []; - const decoded = updateExceptionListSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should accept an undefined for "list_id" and generate a correct body not counting the uuid', () => { - const inputPayload = getUpdateExceptionListSchemaMock(); - delete inputPayload.list_id; - const decoded = updateExceptionListSchema.decode(inputPayload); - const checked = exactCheck(inputPayload, decoded); - const message = pipe(checked, foldLeftRight); - delete (message.schema as UpdateExceptionListSchema).list_id; - expect(message.schema).toEqual(inputPayload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: UpdateExceptionListSchema & { - extraKey?: string; - } = getUpdateExceptionListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = updateExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.ts deleted file mode 100644 index 62add37568ba3..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { version } from '@kbn/securitysolution-io-ts-types'; -import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { Tags, tags } from '../../common/tags'; -import { NamespaceType } from '../../common/default_namespace'; -import { description } from '../../common/description'; -import { name } from '../../common/name'; -import { _version } from '../../common/underscore_version'; -import { exceptionListType } from '../../common/exception_list'; -import { id } from '../../common/id'; -import { list_id } from '../../common/list_id'; -import { meta } from '../../common/meta'; -import { namespace_type } from '../../common/namespace_type'; - -export const updateExceptionListSchema = t.intersection([ - t.exact( - t.type({ - description, - name, - type: exceptionListType, - }) - ), - t.exact( - t.partial({ - _version, // defaults to undefined if not set during decode - id, // defaults to undefined if not set during decode - list_id, // defaults to undefined if not set during decode - meta, // defaults to undefined if not set during decode - namespace_type, // defaults to 'single' if not set during decode - os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode - tags, // defaults to empty array if not set during decode - version, // defaults to undefined if not set during decode - }) - ), -]); - -export type UpdateExceptionListSchema = t.OutputOf; - -// This type is used after a decode since the arrays turn into defaults of empty arrays. -export type UpdateExceptionListSchemaDecoded = Omit< - RequiredKeepUndefined>, - 'tags | namespace_type' | 'os_types' -> & { - tags: Tags; - namespace_type: NamespaceType; - os_types: OsTypeArray; -}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.mock.ts deleted file mode 100644 index 9c3b2dbbd7d35..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.mock.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ID, LIST_ITEM_ID, META, VALUE } from '../../constants/index.mock'; - -import { UpdateListItemSchema } from '.'; - -export const getUpdateListItemSchemaMock = (): UpdateListItemSchema => ({ - id: ID, - meta: META, - value: VALUE, -}); - -/** - * Useful for end to end testing - */ -export const getUpdateMinimalListItemSchemaMock = (): UpdateListItemSchema => ({ - id: LIST_ITEM_ID, - value: VALUE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.test.ts deleted file mode 100644 index 6c7637cbde05e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { UpdateListItemSchema, updateListItemSchema } from '.'; -import { getUpdateListItemSchemaMock } from './index.mock'; - -describe('update_list_item_schema', () => { - test('it should validate a typical list item request', () => { - const payload = getUpdateListItemSchemaMock(); - const decoded = updateListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "meta" but strip it out', () => { - const payload = getUpdateListItemSchemaMock(); - const outputPayload = getUpdateListItemSchemaMock(); - delete payload.meta; - const decoded = updateListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete outputPayload.meta; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: UpdateListItemSchema & { - extraKey?: string; - } = getUpdateListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = updateListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.ts deleted file mode 100644 index 613dde36ef0f7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { _version } from '../../common/underscore_version'; -import { id } from '../../common/id'; -import { value } from '../../common/value'; -import { meta } from '../../common/meta'; - -export const updateListItemSchema = t.intersection([ - t.exact( - t.type({ - id, - value, - }) - ), - t.exact( - t.partial({ - _version, // defaults to undefined if not set during decode - meta, // defaults to undefined if not set during decode - }) - ), -]); - -export type UpdateListItemSchema = t.OutputOf; -export type UpdateListItemSchemaDecoded = RequiredKeepUndefined< - t.TypeOf ->; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.mock.ts deleted file mode 100644 index 5f1fc8fe926d5..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.mock.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DESCRIPTION, LIST_ID, META, NAME, _VERSION } from '../../constants/index.mock'; - -import { UpdateListSchema } from '.'; - -export const getUpdateListSchemaMock = (): UpdateListSchema => ({ - _version: _VERSION, - description: DESCRIPTION, - id: LIST_ID, - meta: META, - name: NAME, -}); - -/** - * Useful for end to end tests and other mechanisms which want to fill in the values - * after doing a get of the structure. - */ -export const getUpdateMinimalListSchemaMock = (): UpdateListSchema => ({ - description: DESCRIPTION, - id: LIST_ID, - name: NAME, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.test.ts deleted file mode 100644 index cac97d7c32cf2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { UpdateListSchema, updateListSchema } from '.'; -import { getUpdateListSchemaMock } from './index.mock'; - -describe('update_list_schema', () => { - test('it should validate a typical list request', () => { - const payload = getUpdateListSchemaMock(); - const decoded = updateListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "meta" but strip it out', () => { - const payload = getUpdateListSchemaMock(); - const outputPayload = getUpdateListSchemaMock(); - delete payload.meta; - const decoded = updateListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - delete outputPayload.meta; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(outputPayload); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: UpdateListSchema & { - extraKey?: string; - } = getUpdateListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = updateListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.ts deleted file mode 100644 index 41ddb81c36e38..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { version } from '@kbn/securitysolution-io-ts-types'; -import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; -import { id } from '../../common/id'; -import { name } from '../../common/name'; -import { description } from '../../common/description'; -import { _version } from '../../common/underscore_version'; -import { meta } from '../../common/meta'; - -export const updateListSchema = t.intersection([ - t.exact( - t.type({ - description, - id, - name, - }) - ), - t.exact( - t.partial({ - _version, // defaults to undefined if not set during decode - meta, // defaults to undefined if not set during decode - version, // defaults to undefined if not set during decode - }) - ), -]); - -export type UpdateListSchema = t.OutputOf; -export type UpdateListSchemaDecoded = RequiredKeepUndefined>; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.mock.ts deleted file mode 100644 index c532dd7401971..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.mock.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { AcknowledgeSchema } from '.'; - -export const getAcknowledgeSchemaResponseMock = (): AcknowledgeSchema => ({ - acknowledged: true, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.test.ts deleted file mode 100644 index 2d3086b023153..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getAcknowledgeSchemaResponseMock } from './index.mock'; -import { AcknowledgeSchema, acknowledgeSchema } from '.'; - -describe('acknowledge_schema', () => { - test('it should validate a typical response', () => { - const payload = getAcknowledgeSchemaResponseMock(); - const decoded = acknowledgeSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - test('it should NOT accept an undefined for "ok"', () => { - const payload = getAcknowledgeSchemaResponseMock(); - // @ts-expect-error - delete payload.acknowledged; - const decoded = acknowledgeSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "acknowledged"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: AcknowledgeSchema & { extraKey?: string } = getAcknowledgeSchemaResponseMock(); - payload.extraKey = 'some new value'; - const decoded = acknowledgeSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.ts deleted file mode 100644 index d506f038534d9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const acknowledgeSchema = t.exact(t.type({ acknowledged: t.boolean })); - -export type AcknowledgeSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.test.ts deleted file mode 100644 index 52c72cf0e8cbc..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { CreateEndpointListSchema, createEndpointListSchema } from '.'; -import { getExceptionListSchemaMock } from '../exception_list_schema/index.mock'; - -describe('create_endpoint_list_schema', () => { - test('it should validate a typical endpoint list response', () => { - const payload = getExceptionListSchemaMock(); - const decoded = createEndpointListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an empty object when an endpoint list already exists', () => { - const payload: CreateEndpointListSchema = {}; - const decoded = createEndpointListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "list_id"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.list_id; - const decoded = createEndpointListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'invalid keys "_version,created_at,created_by,description,id,immutable,meta,{},name,namespace_type,os_types,["linux"],tags,["user added string for a tag","malware"],tie_breaker_id,type,updated_at,updated_by,version"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT allow missing fields', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.list_id; - const decoded = createEndpointListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors)).length).toEqual(1); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: CreateEndpointListSchema & { - extraKey?: string; - } = getExceptionListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = createEndpointListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.ts deleted file mode 100644 index cdcdc8e67e07c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { exceptionListSchema } from '../exception_list_schema'; - -export const createEndpointListSchema = t.union([exceptionListSchema, t.exact(t.type({}))]); - -export type CreateEndpointListSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.mock.ts deleted file mode 100644 index 2c0449ea900ee..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.mock.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - COMMENTS, - DATE_NOW, - DESCRIPTION, - ELASTIC_USER, - ENTRIES, - ITEM_ID, - ITEM_TYPE, - LIST_ID, - META, - NAME, - NAMESPACE_TYPE, - OS_TYPES, - TIE_BREAKER, - USER, -} from '../../constants/index.mock'; - -import { ExceptionListItemSchema } from '.'; - -export const getExceptionListItemSchemaMock = ( - overrides?: Partial -): ExceptionListItemSchema => ({ - _version: undefined, - comments: COMMENTS, - created_at: DATE_NOW, - created_by: USER, - description: DESCRIPTION, - entries: ENTRIES, - expire_time: undefined, - id: '1', - item_id: 'endpoint_list_item', - list_id: 'endpoint_list_id', - meta: META, - name: NAME, - namespace_type: NAMESPACE_TYPE, - os_types: ['linux'], - tags: ['user added string for a tag', 'malware'], - tie_breaker_id: TIE_BREAKER, - type: ITEM_TYPE, - updated_at: DATE_NOW, - updated_by: USER, - ...(overrides || {}), -}); - -/** - * This is useful for end to end tests where we remove the auto generated parts for comparisons - * such as created_at, updated_at, and id. - */ -export const getExceptionListItemResponseMockWithoutAutoGeneratedValues = - (): Partial => ({ - comments: [], - created_by: ELASTIC_USER, - description: DESCRIPTION, - entries: ENTRIES, - item_id: ITEM_ID, - list_id: LIST_ID, - name: NAME, - namespace_type: 'single', - os_types: OS_TYPES, - tags: [], - type: ITEM_TYPE, - updated_by: ELASTIC_USER, - }); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.test.ts deleted file mode 100644 index 9c98d97a596ab..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.test.ts +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getExceptionListItemSchemaMock } from './index.mock'; -import { ExceptionListItemSchema, exceptionListItemSchema } from '.'; - -describe('exception_list_item_schema', () => { - test('it should validate a typical exception list item response', () => { - const payload = getExceptionListItemSchemaMock(); - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "id"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.id; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "list_id"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.list_id; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "item_id"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.item_id; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "item_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "comments"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.comments; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "comments"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "entries"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.entries; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "name"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.name; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "namespace_type" and return "single" as a default value for "namespace_type"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.namespace_type; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as ExceptionListItemSchema).namespace_type).toEqual('single'); - }); - - test('it should NOT accept an undefined for "description"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.description; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "meta"', () => { - const payload = getExceptionListItemSchemaMock(); - delete payload.meta; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "created_at"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.created_at; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "created_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "created_by"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.created_by; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "created_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "tie_breaker_id"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.tie_breaker_id; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "tie_breaker_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "type"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.type; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "updated_at"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.updated_at; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "updated_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "updated_by"', () => { - const payload = getExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.updated_by; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "updated_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ExceptionListItemSchema & { - extraKey?: string; - } = getExceptionListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = exceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.ts deleted file mode 100644 index 5408aa581bdfa..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { namespace_type } from '../../common/namespace_type'; -import { metaOrUndefined } from '../../common/meta'; -import { name } from '../../common/name'; -import { created_at } from '../../common/created_at'; -import { created_by } from '../../common/created_by'; -import { id } from '../../common/id'; -import { tie_breaker_id } from '../../common/tie_breaker_id'; -import { updated_at } from '../../common/updated_at'; -import { updated_by } from '../../common/updated_by'; -import { list_id } from '../../common/list_id'; -import { description } from '../../common/description'; -import { osTypeArray } from '../../common/os_type'; -import { tags } from '../../common/tags'; -import { _versionOrUndefined } from '../../common/underscore_version'; -import { commentsArray } from '../../common/comment'; -import { entriesArray } from '../../common/entries'; -import { item_id } from '../../common/item_id'; -import { exceptionListItemType } from '../../common/exception_list_item_type'; -import { expireTimeOrUndefined } from '../../common/expire_time'; - -export const exceptionListItemSchema = t.exact( - t.type({ - _version: _versionOrUndefined, - comments: commentsArray, - created_at, - created_by, - description, - entries: entriesArray, - expire_time: expireTimeOrUndefined, - id, - item_id, - list_id, - meta: metaOrUndefined, - name, - namespace_type, - os_types: osTypeArray, - tags, - tie_breaker_id, - type: exceptionListItemType, - updated_at, - updated_by, - }) -); - -export type ExceptionListItemSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts deleted file mode 100644 index de2efb85c3379..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - DATE_NOW, - DESCRIPTION, - ELASTIC_USER, - ENDPOINT_TYPE, - IMMUTABLE, - LIST_ID, - META, - NAME, - TIE_BREAKER, - USER, - VERSION, - _VERSION, -} from '../../constants/index.mock'; -import { - ENDPOINT_LIST_ID, - ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, - ENDPOINT_TRUSTED_APPS_LIST_ID, - ENDPOINT_TRUSTED_APPS_LIST_NAME, -} from '@kbn/securitysolution-list-constants'; - -import { ExceptionListSchema } from '.'; - -export const getExceptionListSchemaMock = (): ExceptionListSchema => ({ - _version: _VERSION, - created_at: DATE_NOW, - created_by: USER, - description: DESCRIPTION, - id: '1', - immutable: IMMUTABLE, - list_id: ENDPOINT_LIST_ID, - meta: META, - name: 'Sample Endpoint Exception List', - namespace_type: 'agnostic', - os_types: ['linux'], - tags: ['user added string for a tag', 'malware'], - tie_breaker_id: TIE_BREAKER, - type: ENDPOINT_TYPE, - updated_at: DATE_NOW, - updated_by: 'user_name', - version: VERSION, -}); - -export const getTrustedAppsListSchemaMock = (): ExceptionListSchema => { - return { - ...getExceptionListSchemaMock(), - description: ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, - list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, - name: ENDPOINT_TRUSTED_APPS_LIST_NAME, - }; -}; - -/** - * This is useful for end to end tests where we remove the auto generated parts for comparisons - * such as created_at, updated_at, and id. - */ -export const getExceptionResponseMockWithoutAutoGeneratedValues = - (): Partial => ({ - created_by: ELASTIC_USER, - description: DESCRIPTION, - immutable: IMMUTABLE, - list_id: LIST_ID, - name: NAME, - namespace_type: 'single', - os_types: [], - tags: [], - type: ENDPOINT_TYPE, - updated_by: ELASTIC_USER, - version: VERSION, - }); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.test.ts deleted file mode 100644 index e8dc043bd6b07..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.test.ts +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getExceptionListSchemaMock } from './index.mock'; -import { ExceptionListSchema, exceptionListSchema } from '.'; - -describe('exception_list_schema', () => { - test('it should validate a typical exception list response', () => { - const payload = getExceptionListSchemaMock(); - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "id"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.id; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "list_id"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.list_id; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "name"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.name; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "namespace_type" and make "namespace_type" that of "single"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.namespace_type; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as ExceptionListSchema).namespace_type).toEqual('single'); - }); - - test('it should NOT accept an undefined for "description"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.description; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "meta"', () => { - const payload = getExceptionListSchemaMock(); - delete payload.meta; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "created_at"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.created_at; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "created_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "created_by"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.created_by; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "created_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "tie_breaker_id"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.tie_breaker_id; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "tie_breaker_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "type"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.type; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "updated_at"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.updated_at; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "updated_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "updated_by"', () => { - const payload = getExceptionListSchemaMock(); - // @ts-expect-error - delete payload.updated_by; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "updated_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ExceptionListSchema & { - extraKey?: string; - } = getExceptionListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = exceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.ts deleted file mode 100644 index 0667153c27776..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { version } from '@kbn/securitysolution-io-ts-types'; -import { _versionOrUndefined } from '../../common/underscore_version'; -import { namespace_type } from '../../common/namespace_type'; -import { metaOrUndefined } from '../../common/meta'; -import { name } from '../../common/name'; -import { created_at } from '../../common/created_at'; -import { created_by } from '../../common/created_by'; -import { id } from '../../common/id'; -import { tie_breaker_id } from '../../common/tie_breaker_id'; -import { immutable } from '../../common/immutable'; -import { updated_at } from '../../common/updated_at'; -import { updated_by } from '../../common/updated_by'; -import { list_id } from '../../common/list_id'; -import { description } from '../../common/description'; -import { osTypeArray } from '../../common/os_type'; -import { exceptionListType } from '../../common/exception_list'; -import { tags } from '../../common/tags'; - -export const exceptionListSchema = t.exact( - t.type({ - _version: _versionOrUndefined, - created_at, - created_by, - description, - id, - immutable, - list_id, - meta: metaOrUndefined, - name, - namespace_type, - os_types: osTypeArray, - tags, - tie_breaker_id, - type: exceptionListType, - updated_at, - updated_by, - version, - }) -); - -export type ExceptionListSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts deleted file mode 100644 index 1decbde1374b0..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ExceptionListSummarySchema } from '.'; - -export const getListSummaryResponseMock = (): ExceptionListSummarySchema => ({ - windows: 0, - linux: 1, - macos: 2, - total: 3, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts deleted file mode 100644 index ad1d8b737e46d..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getListSummaryResponseMock } from './index.mock'; -import { ExceptionListSummarySchema, exceptionListSummarySchema } from '.'; - -describe('list_summary_schema', () => { - test('it should validate a typical list summary response', () => { - const payload = getListSummaryResponseMock(); - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "windows"', () => { - const payload = getListSummaryResponseMock(); - // @ts-expect-error - delete payload.windows; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "windows"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "linux"', () => { - const payload = getListSummaryResponseMock(); - // @ts-expect-error - delete payload.linux; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "linux"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "macos"', () => { - const payload = getListSummaryResponseMock(); - // @ts-expect-error - delete payload.macos; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "macos"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "total"', () => { - const payload = getListSummaryResponseMock(); - // @ts-expect-error - delete payload.total; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "total"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ExceptionListSummarySchema & { - extraKey?: string; - } = getListSummaryResponseMock(); - payload.extraKey = 'some new value'; - const decoded = exceptionListSummarySchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts deleted file mode 100644 index a14eaba10b78f..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; -import * as t from 'io-ts'; - -export const exceptionListSummarySchema = t.exact( - t.type({ - windows: PositiveInteger, - linux: PositiveInteger, - macos: PositiveInteger, - total: PositiveInteger, - }) -); - -export type ExceptionListSummarySchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.mock.ts deleted file mode 100644 index 7f6ec6e8bd5c1..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.mock.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FoundAllListItemsSchema } from '.'; -import { getListItemResponseMock } from '../list_item_schema/index.mock'; - -export const getFoundAllListItemsSchemaMock = (): FoundAllListItemsSchema => ({ - data: [getListItemResponseMock()], - total: 1, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.ts deleted file mode 100644 index f8e6dc43647fd..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { listItemSchema } from '../list_item_schema'; -import { total } from '../../common/total'; - -export const foundAllListItemsSchema = t.exact( - t.type({ - data: t.array(listItemSchema), - total, - }) -); - -export type FoundAllListItemsSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.mock.ts deleted file mode 100644 index 8a7abc59a9cdc..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FoundExceptionListItemSchema } from '.'; -import { getExceptionListItemSchemaMock } from '../exception_list_item_schema/index.mock'; - -export const getFoundExceptionListItemSchemaMock = (): FoundExceptionListItemSchema => ({ - data: [getExceptionListItemSchemaMock()], - page: 1, - per_page: 1, - total: 1, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.test.ts deleted file mode 100644 index eeaeee26fac49..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.test.ts +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getFoundExceptionListItemSchemaMock } from './index.mock'; -import { FoundExceptionListItemSchema, foundExceptionListItemSchema } from '.'; -import { ExceptionListItemSchema } from '../exception_list_item_schema'; -import { getExceptionListItemSchemaMock } from '../exception_list_item_schema/index.mock'; - -describe('found_exception_list_item_schema', () => { - test('it should validate a typical exception list response', () => { - const payload = getFoundExceptionListItemSchemaMock(); - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept a malformed exception list item within "data"', () => { - const item: Omit & { - entries?: string; - } = { ...getExceptionListItemSchemaMock(), entries: 'I should be an array' }; - const payload: Omit & { - data?: Array< - Omit & { - entries?: string; - } - >; - } = { ...getFoundExceptionListItemSchemaMock(), data: [item] }; - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "I should be an array" supplied to "data,entries"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept a string for "page"', () => { - const payload: Omit & { - page?: string; - } = { ...getFoundExceptionListItemSchemaMock(), page: '1' }; - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "page"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept a string for "per_page"', () => { - const payload: Omit & { - per_page?: string; - } = { ...getFoundExceptionListItemSchemaMock(), per_page: '20' }; - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "20" supplied to "per_page"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept a string for "total"', () => { - const payload: Omit & { - total?: string; - } = { ...getFoundExceptionListItemSchemaMock(), total: '1' }; - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "total"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "page"', () => { - const payload = getFoundExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.page; - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "page"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "per_page"', () => { - const payload = getFoundExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.per_page; - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "per_page"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "total"', () => { - const payload = getFoundExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.total; - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "total"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "data"', () => { - const payload = getFoundExceptionListItemSchemaMock(); - // @ts-expect-error - delete payload.data; - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "data"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: FoundExceptionListItemSchema & { - extraKey?: string; - } = getFoundExceptionListItemSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = foundExceptionListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.ts deleted file mode 100644 index 6e34672f3349c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { page } from '../../common/page'; -import { per_page } from '../../common/per_page'; -import { pitId } from '../../common/pit'; -import { total } from '../../common/total'; -import { exceptionListItemSchema } from '../exception_list_item_schema'; - -export const foundExceptionListItemSchema = t.intersection([ - t.exact( - t.type({ - data: t.array(exceptionListItemSchema), - page, - per_page, - total, - }) - ), - t.exact( - t.partial({ - pit: pitId, - }) - ), -]); - -export type FoundExceptionListItemSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.mock.ts deleted file mode 100644 index 5a4aa9fcbe577..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.mock.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FoundExceptionListSchema } from '.'; -import { getExceptionListSchemaMock } from '../exception_list_schema/index.mock'; - -export const getFoundExceptionListSchemaMock = (): FoundExceptionListSchema => ({ - data: [getExceptionListSchemaMock()], - page: 1, - per_page: 1, - total: 1, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.test.ts deleted file mode 100644 index 07b302c801708..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.test.ts +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getFoundExceptionListSchemaMock } from './index.mock'; -import { FoundExceptionListSchema, foundExceptionListSchema } from '.'; -import { getExceptionListSchemaMock } from '../exception_list_schema/index.mock'; -import { ExceptionListSchema } from '../exception_list_schema'; - -describe('exception_list_schema', () => { - test('it should validate a typical exception list response', () => { - const payload = getFoundExceptionListSchemaMock(); - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept a malformed exception list item within "data"', () => { - const item: Omit & { - entries?: string[]; - } = { ...getExceptionListSchemaMock(), entries: ['I should not be here'] }; - const payload: Omit & { - data?: Array< - Omit & { - entries?: string[]; - } - >; - } = { ...getFoundExceptionListSchemaMock(), data: [item] }; - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'invalid keys "entries,["I should not be here"]"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept a string for "page"', () => { - const payload: Omit & { - page?: string; - } = { ...getFoundExceptionListSchemaMock(), page: '1' }; - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "page"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept a string for "per_page"', () => { - const payload: Omit & { - per_page?: string; - } = { ...getFoundExceptionListSchemaMock(), per_page: '20' }; - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "20" supplied to "per_page"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept a string for "total"', () => { - const payload: Omit & { - total?: string; - } = { ...getFoundExceptionListSchemaMock(), total: '1' }; - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "total"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "page"', () => { - const payload = getFoundExceptionListSchemaMock(); - // @ts-expect-error - delete payload.page; - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "page"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "per_page"', () => { - const payload = getFoundExceptionListSchemaMock(); - // @ts-expect-error - delete payload.per_page; - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "per_page"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "total"', () => { - const payload = getFoundExceptionListSchemaMock(); - // @ts-expect-error - delete payload.total; - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "total"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "data"', () => { - const payload = getFoundExceptionListSchemaMock(); - // @ts-expect-error - delete payload.data; - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "data"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: FoundExceptionListSchema & { - extraKey?: string; - } = getFoundExceptionListSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = foundExceptionListSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.ts deleted file mode 100644 index de4a222b61e78..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { page } from '../../common/page'; -import { per_page } from '../../common/per_page'; -import { pitId } from '../../common/pit'; -import { total } from '../../common/total'; - -import { exceptionListSchema } from '../exception_list_schema'; - -export const foundExceptionListSchema = t.intersection([ - t.exact( - t.type({ - data: t.array(exceptionListSchema), - page, - per_page, - total, - }) - ), - t.exact(t.partial({ pit: pitId })), -]); - -export type FoundExceptionListSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.mock.ts deleted file mode 100644 index 3f20835657432..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.mock.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FoundListItemSchema } from '.'; -import { getListItemResponseMock } from '../list_item_schema/index.mock'; - -export const getFoundListItemSchemaMock = (): FoundListItemSchema => ({ - cursor: 'WzI1LFsiNmE3NmI2OWQtODBkZi00YWIyLThjM2UtODVmNDY2YjA2YTBlIl1d', - data: [getListItemResponseMock()], - page: 1, - per_page: 25, - total: 1, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.ts deleted file mode 100644 index 872a178b2f130..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { listItemSchema } from '../list_item_schema'; -import { cursor } from '../../common/cursor'; -import { page } from '../../common/page'; -import { per_page } from '../../common/per_page'; -import { total } from '../../common/total'; - -export const foundListItemSchema = t.exact( - t.type({ - cursor, - data: t.array(listItemSchema), - page, - per_page, - total, - }) -); - -export type FoundListItemSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.mock.ts deleted file mode 100644 index 232de4d47c156..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.mock.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FoundListSchema } from '.'; -import { getListResponseMock } from '../list_schema/index.mock'; - -export const getFoundListSchemaMock = (): FoundListSchema => ({ - cursor: '123', - data: [getListResponseMock()], - page: 1, - per_page: 1, - total: 1, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.ts deleted file mode 100644 index 6b97b8c73e634..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { listSchema } from '../list_schema'; -import { cursor } from '../../common/cursor'; -import { page } from '../../common/page'; -import { per_page } from '../../common/per_page'; -import { total } from '../../common/total'; - -export const foundListSchema = t.exact( - t.type({ - cursor, - data: t.array(listSchema), - page, - per_page, - total, - }) -); - -export type FoundListSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.mock.ts deleted file mode 100644 index bd654ccde56e8..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.mock.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FoundListsBySizeSchema } from '.'; -import { getListResponseMock } from '../list_schema/index.mock'; - -export const getFoundListsBySizeSchemaMock = (): FoundListsBySizeSchema => ({ - smallLists: [getListResponseMock()], - largeLists: [getListResponseMock()], -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.ts deleted file mode 100644 index b4d41484bf269..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { listSchema } from '../list_schema'; - -export const foundListsBySizeSchema = t.exact( - t.type({ - largeLists: t.array(listSchema), - smallLists: t.array(listSchema), - }) -); - -export type FoundListsBySizeSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.mock.ts deleted file mode 100644 index b1502381013c3..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.mock.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ImportExceptionsResponseSchema } from '.'; - -export const getImportExceptionsResponseSchemaMock = ( - success = 0, - lists = 0, - items = 0 -): ImportExceptionsResponseSchema => ({ - errors: [], - success: true, - success_count: success, - success_exception_lists: true, - success_count_exception_lists: lists, - success_exception_list_items: true, - success_count_exception_list_items: items, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.test.ts deleted file mode 100644 index 81dd87bf19a56..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { importExceptionsResponseSchema, ImportExceptionsResponseSchema } from '.'; -import { getImportExceptionsResponseSchemaMock } from './index.mock'; - -describe('importExceptionsResponseSchema', () => { - test('it should validate a typical exceptions import response', () => { - const payload = getImportExceptionsResponseSchemaMock(); - const decoded = importExceptionsResponseSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "errors"', () => { - const payload: Partial> = - getImportExceptionsResponseSchemaMock(); - delete payload.errors; - const decoded = importExceptionsResponseSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "errors"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "success"', () => { - const payload: Partial> = - getImportExceptionsResponseSchemaMock(); - delete payload.success; - const decoded = importExceptionsResponseSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "success"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "success_count"', () => { - const payload: Partial> = - getImportExceptionsResponseSchemaMock(); - delete payload.success_count; - const decoded = importExceptionsResponseSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "success_count"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "success_exception_lists"', () => { - const payload: Partial> = - getImportExceptionsResponseSchemaMock(); - delete payload.success_exception_lists; - const decoded = importExceptionsResponseSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "success_exception_lists"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "success_count_exception_lists"', () => { - const payload: Partial> = - getImportExceptionsResponseSchemaMock(); - delete payload.success_count_exception_lists; - const decoded = importExceptionsResponseSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "success_count_exception_lists"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "success_exception_list_items"', () => { - const payload: Partial> = - getImportExceptionsResponseSchemaMock(); - delete payload.success_exception_list_items; - const decoded = importExceptionsResponseSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "success_exception_list_items"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "success_count_exception_list_items"', () => { - const payload: Partial> = - getImportExceptionsResponseSchemaMock(); - delete payload.success_count_exception_list_items; - const decoded = importExceptionsResponseSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "success_count_exception_list_items"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ImportExceptionsResponseSchema & { - extraKey?: string; - } = getImportExceptionsResponseSchemaMock(); - payload.extraKey = 'some new value'; - const decoded = importExceptionsResponseSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.ts deleted file mode 100644 index b976ab298e0c7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; - -import { id } from '../../common/id'; -import { list_id } from '../../common/list_id'; -import { item_id } from '../../common/item_id'; - -export const bulkErrorErrorSchema = t.exact( - t.type({ - status_code: t.number, - message: t.string, - }) -); - -export const bulkErrorSchema = t.intersection([ - t.exact( - t.type({ - error: bulkErrorErrorSchema, - }) - ), - t.partial({ - id, - list_id, - item_id, - }), -]); - -export type BulkErrorSchema = t.TypeOf; - -export const importExceptionsResponseSchema = t.exact( - t.type({ - errors: t.array(bulkErrorSchema), - success: t.boolean, - success_count: PositiveInteger, - success_exception_lists: t.boolean, - success_count_exception_lists: PositiveInteger, - success_exception_list_items: t.boolean, - success_count_exception_list_items: PositiveInteger, - }) -); - -export type ImportExceptionsResponseSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts deleted file mode 100644 index 49c42783473d7..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './acknowledge_schema'; -export * from './create_endpoint_list_schema'; -export * from './exception_list_schema'; -export * from './exception_list_item_schema'; -export * from './found_exception_list_item_schema'; -export * from './found_exception_list_schema'; -export * from './found_all_list_items_schema'; -export * from './found_lists_by_size_schema'; -export * from './found_list_item_schema'; -export * from './found_list_schema'; -export * from './import_exceptions_schema'; -export * from './list_item_schema'; -export * from './list_schema'; -export * from './exception_list_summary_schema'; -export * from './list_item_index_exist_schema'; -export * from './search_list_item_schema'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.mock.ts deleted file mode 100644 index eff892b3f00bb..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.mock.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ListItemIndexExistSchema } from '.'; - -export const getListItemIndexExistSchemaResponseMock = (): ListItemIndexExistSchema => ({ - list_index: true, - list_item_index: true, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.test.ts deleted file mode 100644 index 2827cd3627344..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getListItemIndexExistSchemaResponseMock } from './index.mock'; -import { ListItemIndexExistSchema, listItemIndexExistSchema } from '.'; - -describe('list_item_index_exist_schema', () => { - test('it should validate a typical list item request', () => { - const payload = getListItemIndexExistSchemaResponseMock(); - const decoded = listItemIndexExistSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "list_index"', () => { - const payload = getListItemIndexExistSchemaResponseMock(); - // @ts-expect-error - delete payload.list_index; - const decoded = listItemIndexExistSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_index"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "list_item_index"', () => { - const payload = getListItemIndexExistSchemaResponseMock(); - // @ts-expect-error - delete payload.list_item_index; - const decoded = listItemIndexExistSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_item_index"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ListItemIndexExistSchema & { - extraKey?: string; - } = getListItemIndexExistSchemaResponseMock(); - payload.extraKey = 'some new value'; - const decoded = listItemIndexExistSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.ts deleted file mode 100644 index 494af4e3e7590..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -export const listItemIndexExistSchema = t.exact( - t.type({ - list_index: t.boolean, - list_item_index: t.boolean, - }) -); - -export type ListItemIndexExistSchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.mock.ts deleted file mode 100644 index 22c2e5ae07f61..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.mock.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ListItemSchema } from '.'; -import { - DATE_NOW, - ELASTIC_USER, - LIST_ID, - LIST_ITEM_ID, - META, - TIE_BREAKER, - TYPE, - USER, - VALUE, -} from '../../constants/index.mock'; - -export const getListItemResponseMock = (): ListItemSchema => ({ - _version: undefined, - '@timestamp': DATE_NOW, - created_at: DATE_NOW, - created_by: USER, - deserializer: undefined, - id: LIST_ITEM_ID, - list_id: LIST_ID, - meta: META, - serializer: undefined, - tie_breaker_id: TIE_BREAKER, - type: TYPE, - updated_at: DATE_NOW, - updated_by: USER, - value: VALUE, -}); - -/** - * This is useful for end to end tests where we remove the auto generated parts for comparisons - * such as created_at, updated_at, and id. - */ -export const getListItemResponseMockWithoutAutoGeneratedValues = (): Partial => ({ - created_by: ELASTIC_USER, - list_id: LIST_ID, - type: TYPE, - updated_by: ELASTIC_USER, - value: VALUE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.test.ts deleted file mode 100644 index 5b4238e136dc6..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.test.ts +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getListItemResponseMock } from './index.mock'; -import { ListItemSchema, listItemSchema } from '.'; - -describe('list_item_schema', () => { - test('it should validate a typical list item response', () => { - const payload = getListItemResponseMock(); - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "id"', () => { - const payload = getListItemResponseMock(); - // @ts-expect-error - delete payload.id; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "list_id"', () => { - const payload = getListItemResponseMock(); - // @ts-expect-error - delete payload.list_id; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "list_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "meta"', () => { - const payload = getListItemResponseMock(); - delete payload.meta; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "serializer"', () => { - const payload = getListItemResponseMock(); - delete payload.serializer; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "deserializer"', () => { - const payload = getListItemResponseMock(); - delete payload.deserializer; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "created_at"', () => { - const payload = getListItemResponseMock(); - // @ts-expect-error - delete payload.created_at; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "created_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "created_by"', () => { - const payload = getListItemResponseMock(); - // @ts-expect-error - delete payload.created_by; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "created_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "tie_breaker_id"', () => { - const payload = getListItemResponseMock(); - // @ts-expect-error - delete payload.tie_breaker_id; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "tie_breaker_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "type"', () => { - const payload = getListItemResponseMock(); - // @ts-expect-error - delete payload.type; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "updated_at"', () => { - const payload = getListItemResponseMock(); - // @ts-expect-error - delete payload.updated_at; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "updated_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "updated_by"', () => { - const payload = getListItemResponseMock(); - // @ts-expect-error - delete payload.updated_by; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "updated_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "value"', () => { - const payload = getListItemResponseMock(); - // @ts-expect-error - delete payload.value; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "value"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ListItemSchema & { extraKey?: string } = getListItemResponseMock(); - payload.extraKey = 'some new value'; - const decoded = listItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.ts deleted file mode 100644 index 869ca695fa42e..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; - -import { _versionOrUndefined } from '../../common/underscore_version'; -import { deserializerOrUndefined } from '../../common/deserializer'; -import { metaOrUndefined } from '../../common/meta'; -import { timestampOrUndefined } from '../../common/timestamp'; -import { serializerOrUndefined } from '../../common/serializer'; -import { created_at } from '../../common/created_at'; -import { created_by } from '../../common/created_by'; -import { id } from '../../common/id'; -import { tie_breaker_id } from '../../common/tie_breaker_id'; -import { type } from '../../common/type'; -import { updated_at } from '../../common/updated_at'; -import { updated_by } from '../../common/updated_by'; -import { list_id } from '../../common/list_id'; -import { value } from '../../common/value'; - -export const listItemSchema = t.exact( - t.type({ - _version: _versionOrUndefined, - '@timestamp': timestampOrUndefined, - created_at, - created_by, - deserializer: deserializerOrUndefined, - id, - list_id, - meta: metaOrUndefined, - serializer: serializerOrUndefined, - tie_breaker_id, - type, - updated_at, - updated_by, - value, - }) -); - -export type ListItemSchema = t.TypeOf; - -export const listItemArraySchema = t.array(listItemSchema); -export type ListItemArraySchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.mock.ts deleted file mode 100644 index 7a0b9e01b87c5..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.mock.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ListSchema } from '.'; -import { - DATE_NOW, - DESCRIPTION, - ELASTIC_USER, - IMMUTABLE, - LIST_ID, - META, - NAME, - TIE_BREAKER, - TYPE, - USER, - VERSION, -} from '../../constants/index.mock'; - -export const getListResponseMock = (): ListSchema => ({ - _version: undefined, - '@timestamp': DATE_NOW, - created_at: DATE_NOW, - created_by: USER, - description: DESCRIPTION, - deserializer: undefined, - id: LIST_ID, - immutable: IMMUTABLE, - meta: META, - name: NAME, - serializer: undefined, - tie_breaker_id: TIE_BREAKER, - type: TYPE, - updated_at: DATE_NOW, - updated_by: USER, - version: VERSION, -}); - -/** - * This is useful for end to end tests where we remove the auto generated parts for comparisons - * such as created_at, updated_at, and id. - */ -export const getListResponseMockWithoutAutoGeneratedValues = (): Partial => ({ - created_by: ELASTIC_USER, - description: DESCRIPTION, - immutable: IMMUTABLE, - name: NAME, - type: TYPE, - updated_by: ELASTIC_USER, - version: VERSION, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.test.ts deleted file mode 100644 index 17f25de7d8ec2..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.test.ts +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getListResponseMock } from './index.mock'; -import { ListSchema, listSchema } from '.'; - -describe('list_schema', () => { - test('it should validate a typical list response', () => { - const payload = getListResponseMock(); - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "id"', () => { - const payload = getListResponseMock(); - // @ts-expect-error - delete payload.id; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); - expect(message.schema).toEqual({}); - }); - - test('it should accept an undefined for "meta"', () => { - const payload = getListResponseMock(); - delete payload.meta; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "serializer"', () => { - const payload = getListResponseMock(); - delete payload.serializer; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should accept an undefined for "deserializer"', () => { - const payload = getListResponseMock(); - delete payload.deserializer; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT accept an undefined for "created_at"', () => { - const payload = getListResponseMock(); - // @ts-expect-error - delete payload.created_at; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "created_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "created_by"', () => { - const payload = getListResponseMock(); - // @ts-expect-error - delete payload.created_by; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "created_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "tie_breaker_id"', () => { - const payload = getListResponseMock(); - // @ts-expect-error - delete payload.tie_breaker_id; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "tie_breaker_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "type"', () => { - const payload = getListResponseMock(); - // @ts-expect-error - delete payload.type; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "type"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "updated_at"', () => { - const payload = getListResponseMock(); - // @ts-expect-error - delete payload.updated_at; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "updated_at"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "updated_by"', () => { - const payload = getListResponseMock(); - // @ts-expect-error - delete payload.updated_by; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "updated_by"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "name"', () => { - const payload = getListResponseMock(); - // @ts-expect-error - delete payload.name; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT accept an undefined for "description"', () => { - const payload = getListResponseMock(); - // @ts-expect-error - delete payload.description; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "description"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: ListSchema & { extraKey?: string } = getListResponseMock(); - payload.extraKey = 'some new value'; - const decoded = listSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.ts deleted file mode 100644 index 5029e55df3244..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { version } from '@kbn/securitysolution-io-ts-types'; -import { _versionOrUndefined } from '../../common/underscore_version'; -import { deserializerOrUndefined } from '../../common/deserializer'; -import { metaOrUndefined } from '../../common/meta'; -import { serializerOrUndefined } from '../../common/serializer'; -import { created_at } from '../../common/created_at'; -import { timestampOrUndefined } from '../../common/timestamp'; -import { created_by } from '../../common/created_by'; -import { description } from '../../common/description'; -import { id } from '../../common/id'; -import { immutable } from '../../common/immutable'; -import { name } from '../../common/name'; -import { tie_breaker_id } from '../../common/tie_breaker_id'; -import { type } from '../../common/type'; -import { updated_at } from '../../common/updated_at'; -import { updated_by } from '../../common/updated_by'; - -export const listSchema = t.exact( - t.type({ - _version: _versionOrUndefined, - '@timestamp': timestampOrUndefined, - created_at, - created_by, - description, - deserializer: deserializerOrUndefined, - id, - immutable, - meta: metaOrUndefined, - name, - serializer: serializerOrUndefined, - tie_breaker_id, - type, - updated_at, - updated_by, - version, - }) -); - -export type ListSchema = t.TypeOf; - -export const listArraySchema = t.array(listSchema); -export type ListArraySchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.mock.ts deleted file mode 100644 index 1cab9a6b827c6..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.mock.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { SearchListItemSchema } from '.'; -import { VALUE } from '../../constants/index.mock'; -import { getListItemResponseMock } from '../list_item_schema/index.mock'; - -export const getSearchListItemResponseMock = (): SearchListItemSchema => ({ - items: [getListItemResponseMock()], - value: VALUE, -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.test.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.test.ts deleted file mode 100644 index a6604f39b4626..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { getSearchListItemResponseMock } from './index.mock'; -import { SearchListItemSchema, searchListItemSchema } from '.'; - -describe('search_list_item_schema', () => { - test('it should validate a typical search list item response', () => { - const payload = getSearchListItemResponseMock(); - const decoded = searchListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should NOT validate with an "undefined" for "items"', () => { - const { items, ...noItems } = getSearchListItemResponseMock(); - const decoded = searchListItemSchema.decode(noItems); - const checked = exactCheck(noItems, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "items"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should not allow an extra key to be sent in', () => { - const payload: SearchListItemSchema & { extraKey?: string } = getSearchListItemResponseMock(); - payload.extraKey = 'some new value'; - const decoded = searchListItemSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); - expect(message.schema).toEqual({}); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.ts deleted file mode 100644 index c5a07308dd0f8..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import * as t from 'io-ts'; -import { listItemArraySchema } from '../list_item_schema'; - -/** - * NOTE: Although this is defined within "response" this does not expose a REST API - * endpoint right now for this particular response. Instead this is only used internally - * for the plugins at this moment. If this changes, please remove this message. - */ -export const searchListItemSchema = t.exact( - t.type({ - items: listItemArraySchema, - value: t.unknown, - }) -); - -export type SearchListItemSchema = t.TypeOf; - -export const searchListItemArraySchema = t.array(searchListItemSchema); -export type SearchListItemArraySchema = t.TypeOf; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts deleted file mode 100644 index 9a8cd1e4fab56..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { HttpStart } from '@kbn/core-http-browser'; -import type { NotificationsStart } from '@kbn/core-notifications-browser'; -import type { Filter } from '@kbn/es-query'; -import { NamespaceType } from '../common/default_namespace'; -import { ExceptionListType, ExceptionListTypeEnum } from '../common/exception_list'; -import { Page } from '../common/page'; -import { PerPage } from '../common/per_page'; -import { TotalOrUndefined } from '../common/total'; -import { CreateExceptionListItemSchema } from '../request/create_exception_list_item_schema'; -import { CreateExceptionListSchema } from '../request/create_exception_list_schema'; -import { ExceptionListId } from '../request/get_exception_filter_schema'; -import { UpdateExceptionListItemSchema } from '../request/update_exception_list_item_schema'; -import { UpdateExceptionListSchema } from '../request/update_exception_list_schema'; -import { ExceptionListItemSchema } from '../response/exception_list_item_schema'; -import { ExceptionListSchema } from '../response/exception_list_schema'; - -interface BaseParams { - http: HttpStart; - signal: AbortSignal; -} - -export interface DuplicateExceptionListProps extends BaseParams { - listId: string; - namespaceType: NamespaceType; - includeExpiredExceptions: boolean; -} - -export interface ApiListDuplicateProps - extends Omit { - onError: (err: Error) => void; - onSuccess: (newList: ExceptionListSchema) => void; -} - -export interface ExceptionListFilter { - name?: string | null; - list_id?: string | null; - created_by?: string | null; - types?: ExceptionListTypeEnum[] | null; - tags?: string | null; -} - -export interface UseExceptionListsProps { - errorMessage: string; - filterOptions?: ExceptionListFilter; - http: HttpStart; - namespaceTypes: NamespaceType[]; - notifications: NotificationsStart; - initialPagination?: Pagination; - hideLists?: readonly string[]; - initialSort?: Sort; -} - -export interface UseExceptionListProps { - http: HttpStart; - lists: ExceptionListIdentifiers[]; - onError?: (arg: string[]) => void; - filterOptions: FilterExceptionsOptions[]; - pagination?: Pagination; - showDetectionsListsOnly: boolean; - showEndpointListsOnly: boolean; - matchFilters: boolean; - onSuccess?: (arg: UseExceptionListItemsSuccess) => void; - sort?: Sort; -} - -export interface FilterExceptionsOptions { - filter: string; - tags: string[]; -} - -export interface ApiCallMemoProps { - id: string; - namespaceType: NamespaceType; - onError: (arg: Error) => void; - onSuccess: () => void; -} - -// TODO: Switch to use ApiCallMemoProps -// after cleaning up exceptions/api file to -// remove unnecessary validation checks -export interface ApiListExportProps { - id: string; - includeExpiredExceptions: boolean; - listId: string; - namespaceType: NamespaceType; - onError: (err: Error) => void; - onSuccess: (blob: Blob) => void; -} - -export interface Sort { - field: string; - order: string; -} -export interface Pagination { - page: Page; - perPage: PerPage; - total: TotalOrUndefined; -} - -export interface UseExceptionListItemsSuccess { - exceptions: ExceptionListItemSchema[]; - pagination: Pagination; -} - -export interface ExceptionListIdentifiers { - id: string; - listId: string; - namespaceType: NamespaceType; - type: ExceptionListType; -} - -export interface ApiCallFindListsItemsMemoProps { - lists: ExceptionListIdentifiers[]; - pagination: Partial; - showDetectionsListsOnly: boolean; - showEndpointListsOnly: boolean; - filter?: string; - onError: (arg: string[]) => void; - onSuccess: (arg: UseExceptionListItemsSuccess) => void; -} - -export interface ApiCallGetExceptionFilterFromIdsMemoProps extends GetExceptionFilterOptionalProps { - exceptionListIds: ExceptionListId[]; - onError: (arg: string[]) => void; - onSuccess: (arg: Filter) => void; -} - -export interface ApiCallGetExceptionFilterFromExceptionsMemoProps - extends GetExceptionFilterOptionalProps { - exceptions: Array; - onError: (arg: string[]) => void; - onSuccess: (arg: Filter) => void; -} - -export interface ExportExceptionListProps { - http: HttpStart; - id: string; - listId: string; - namespaceType: NamespaceType; - includeExpiredExceptions: boolean; - signal: AbortSignal; -} - -export interface AddEndpointExceptionListProps { - http: HttpStart; - signal: AbortSignal; -} - -export interface UpdateExceptionListItemProps { - http: HttpStart; - listItem: UpdateExceptionListItemSchema; - signal: AbortSignal; -} - -export interface UpdateExceptionListProps { - http: HttpStart; - list: UpdateExceptionListSchema; - signal: AbortSignal; -} - -export interface AddExceptionListItemProps { - http: HttpStart; - listItem: CreateExceptionListItemSchema; - signal: AbortSignal; -} - -export interface AddExceptionListProps { - http: HttpStart; - list: CreateExceptionListSchema; - signal: AbortSignal; -} - -export interface UseExceptionListsSuccess { - exceptions: ExceptionListSchema[]; - pagination: Pagination; -} - -export interface ApiCallFetchExceptionListsProps { - http: HttpStart; - namespaceTypes: string; - pagination: Partial; - sort?: Sort; - filters: string; - signal: AbortSignal; -} - -export interface ApiCallByIdProps { - http: HttpStart; - id: string; - namespaceType: NamespaceType; - signal: AbortSignal; -} - -export interface ApiCallByListIdProps { - http: HttpStart; - listIds: string[]; - namespaceTypes: NamespaceType[]; - pagination: Partial; - search?: string; - filter?: string; - signal: AbortSignal; -} - -export type AddExceptionList = UpdateExceptionListSchema | CreateExceptionListSchema; - -export interface PersistHookProps { - http: HttpStart; - onError: (arg: Error) => void; -} - -export interface ExceptionList extends ExceptionListSchema { - totalItems: number; -} - -export interface GetExceptionFilterOptionalProps { - signal?: AbortSignal; - chunkSize?: number; - alias?: string; - excludeExceptions?: boolean; -} - -export interface GetExceptionFilterFromExceptionListIdsProps - extends GetExceptionFilterOptionalProps { - http: HttpStart; - exceptionListIds: ExceptionListId[]; -} - -export interface GetExceptionFilterFromExceptionsProps extends GetExceptionFilterOptionalProps { - http: HttpStart; - exceptions: Array; -} - -export interface ExceptionFilterResponse { - filter: Filter; -} diff --git a/packages/kbn-securitysolution-io-ts-list-types/tsconfig.json b/packages/kbn-securitysolution-io-ts-list-types/tsconfig.json deleted file mode 100644 index 706aa6e81fc59..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": ["jest", "node"] - }, - "include": ["**/*.ts"], - "kbn_references": [ - "@kbn/securitysolution-io-ts-types", - "@kbn/securitysolution-io-ts-utils", - "@kbn/securitysolution-list-constants", - "@kbn/es-query", - "@kbn/core-http-browser", - "@kbn/core-notifications-browser", - "@kbn/securitysolution-exceptions-common" - ], - "exclude": ["target/**/*"] -} diff --git a/packages/kbn-securitysolution-io-ts-types/jest.config.js b/packages/kbn-securitysolution-io-ts-types/jest.config.js deleted file mode 100644 index c6efe620b09f8..0000000000000 --- a/packages/kbn-securitysolution-io-ts-types/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-io-ts-types'], -}; diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_uuid/index.test.ts b/packages/kbn-securitysolution-io-ts-types/src/default_uuid/index.test.ts deleted file mode 100644 index c429529167e52..0000000000000 --- a/packages/kbn-securitysolution-io-ts-types/src/default_uuid/index.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; -import { DefaultUuid } from '.'; -import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -describe('default_uuid', () => { - test('it should validate a regular string', () => { - const payload = '1'; - const decoded = DefaultUuid.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('it should not validate a number', () => { - const payload = 5; - const decoded = DefaultUuid.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "DefaultUuid"']); - expect(message.schema).toEqual({}); - }); - - test('it should return a default of a uuid', () => { - const payload = null; - const decoded = DefaultUuid.decode(payload); - const message = pipe(decoded, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toMatch( - /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i - ); - }); -}); diff --git a/packages/kbn-securitysolution-io-ts-types/tsconfig.json b/packages/kbn-securitysolution-io-ts-types/tsconfig.json deleted file mode 100644 index 25b82d38b7dc9..0000000000000 --- a/packages/kbn-securitysolution-io-ts-types/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/securitysolution-io-ts-utils" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-io-ts-utils/jest.config.js b/packages/kbn-securitysolution-io-ts-utils/jest.config.js deleted file mode 100644 index 457ac315951b6..0000000000000 --- a/packages/kbn-securitysolution-io-ts-utils/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-io-ts-utils'], -}; diff --git a/packages/kbn-securitysolution-io-ts-utils/tsconfig.json b/packages/kbn-securitysolution-io-ts-utils/tsconfig.json deleted file mode 100644 index 13f8244edd1ad..0000000000000 --- a/packages/kbn-securitysolution-io-ts-utils/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/datemath" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-list-api/index.ts b/packages/kbn-securitysolution-list-api/index.ts deleted file mode 100644 index fc434f01c7ecb..0000000000000 --- a/packages/kbn-securitysolution-list-api/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './src/api'; -export * from './src/fp_utils'; -export * from './src/list_api'; -export * from './src/list_item_api'; -export * from './src/types'; diff --git a/packages/kbn-securitysolution-list-api/jest.config.js b/packages/kbn-securitysolution-list-api/jest.config.js deleted file mode 100644 index 434cef2b7ca33..0000000000000 --- a/packages/kbn-securitysolution-list-api/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-list-api'], -}; diff --git a/packages/kbn-securitysolution-list-api/package.json b/packages/kbn-securitysolution-list-api/package.json deleted file mode 100644 index bcb7a79accdc5..0000000000000 --- a/packages/kbn-securitysolution-list-api/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/securitysolution-list-api", - "version": "1.0.0", - "description": "security solution list REST API", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-list-api/src/api/index.ts b/packages/kbn-securitysolution-list-api/src/api/index.ts deleted file mode 100644 index 4bd188672e5a9..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/api/index.ts +++ /dev/null @@ -1,666 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", 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, - GetExceptionFilterFromExceptionListIdsProps, - GetExceptionFilterFromExceptionsProps, - ExceptionFilterResponse, - DuplicateExceptionListProps, -} from '@kbn/securitysolution-io-ts-list-types'; - -import { - ENDPOINT_LIST_URL, - INTERNAL_EXCEPTION_FILTER, - EXCEPTION_LIST_ITEM_URL, - EXCEPTION_LIST_URL, -} from '@kbn/securitysolution-list-constants'; -import { toError, toPromise } from '../fp_utils'; - -const version = '2023-10-31'; - -/** - * 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 => - http.fetch(EXCEPTION_LIST_URL, { - body: JSON.stringify(list), - method: 'POST', - signal, - version, - }); - -const addExceptionListWithValidation = async ({ - http, - list, - signal, -}: AddExceptionListProps): Promise => - 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 => - http.fetch(EXCEPTION_LIST_ITEM_URL, { - body: JSON.stringify(listItem), - method: 'POST', - signal, - version, - }); - -const addExceptionListItemWithValidation = async ({ - http, - listItem, - signal, -}: AddExceptionListItemProps): Promise => - 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 => - http.fetch(EXCEPTION_LIST_URL, { - body: JSON.stringify(list), - method: 'PUT', - signal, - version, - }); - -const updateExceptionListWithValidation = async ({ - http, - list, - signal, -}: UpdateExceptionListProps): Promise => - 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 => - http.fetch(EXCEPTION_LIST_ITEM_URL, { - body: JSON.stringify(listItem), - method: 'PUT', - signal, - version, - }); - -const updateExceptionListItemWithValidation = async ({ - http, - listItem, - signal, -}: UpdateExceptionListItemProps): Promise => - 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, - sort, -}: ApiCallFetchExceptionListsProps): Promise => { - const query = { - filter: filters || undefined, - namespace_type: namespaceTypes, - page: pagination.page ? `${pagination.page}` : '1', - per_page: pagination.perPage ? `${pagination.perPage}` : '20', - sort_field: sort?.field ? sort?.field : 'exception-list.created_at', - sort_order: sort?.order ? sort?.order : 'desc', - }; - - return http.fetch(`${EXCEPTION_LIST_URL}/_find`, { - method: 'GET', - query, - signal, - version, - }); -}; - -const fetchExceptionListsWithValidation = async ({ - filters, - http, - namespaceTypes, - pagination, - signal, - sort, -}: ApiCallFetchExceptionListsProps): Promise => - flow( - () => - tryCatch( - () => - fetchExceptionLists({ - filters, - http, - namespaceTypes, - pagination, - signal, - sort, - }), - 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 => - http.fetch(EXCEPTION_LIST_URL, { - method: 'GET', - query: { id, namespace_type: namespaceType }, - signal, - version, - }); - -const fetchExceptionListByIdWithValidation = async ({ - http, - id, - namespaceType, - signal, -}: ApiCallByIdProps): Promise => - 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 search optional - simple search string - * @param filter optional - * @param pagination optional - * @param signal to cancel request - * - * @throws An error if response is not OK - */ -const fetchExceptionListsItemsByListIds = async ({ - http, - listIds, - namespaceTypes, - filter, - pagination, - search, - signal, -}: ApiCallByListIdProps): Promise => { - const query = { - list_id: listIds.join(','), - namespace_type: namespaceTypes.join(','), - page: pagination.page ? `${pagination.page}` : '1', - per_page: pagination.perPage ? `${pagination.perPage}` : '20', - search, - sort_field: 'exception-list.created_at', - sort_order: 'desc', - filter, - }; - - return http.fetch(`${EXCEPTION_LIST_ITEM_URL}/_find`, { - method: 'GET', - query, - signal, - version, - }); -}; - -const fetchExceptionListsItemsByListIdsWithValidation = async ({ - filter, - http, - listIds, - namespaceTypes, - pagination, - search, - signal, -}: ApiCallByListIdProps): Promise => - flow( - () => - tryCatch( - () => - fetchExceptionListsItemsByListIds({ - filter, - http, - listIds, - namespaceTypes, - pagination, - search, - 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 => - http.fetch(EXCEPTION_LIST_ITEM_URL, { - method: 'GET', - query: { id, namespace_type: namespaceType }, - signal, - version, - }); - -const fetchExceptionListItemByIdWithValidation = async ({ - http, - id, - namespaceType, - signal, -}: ApiCallByIdProps): Promise => - 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 => - http.fetch(EXCEPTION_LIST_URL, { - method: 'DELETE', - query: { id, namespace_type: namespaceType }, - signal, - version, - }); - -const deleteExceptionListByIdWithValidation = async ({ - http, - id, - namespaceType, - signal, -}: ApiCallByIdProps): Promise => - 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 => - http.fetch(EXCEPTION_LIST_ITEM_URL, { - method: 'DELETE', - query: { id, namespace_type: namespaceType }, - signal, - version, - }); - -const deleteExceptionListItemByIdWithValidation = async ({ - http, - id, - namespaceType, - signal, -}: ApiCallByIdProps): Promise => - 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 => - http.fetch(ENDPOINT_LIST_URL, { - method: 'POST', - signal, - version, - }); - -const addEndpointExceptionListWithValidation = async ({ - http, - signal, -}: AddEndpointExceptionListProps): Promise => - flow( - () => tryCatch(() => addEndpointExceptionList({ http, signal }), toError), - chain((response) => fromEither(validateEither(createEndpointListSchema, response))), - flow(toPromise) - )(); - -export { addEndpointExceptionListWithValidation as addEndpointExceptionList }; - -/** - * Export an ExceptionList by providing a ExceptionList ID - * - * @param http Kibana http service - * @param id ExceptionList ID (not list_id) - * @param includeExpiredExceptions boolean for including expired exceptions - * @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, - includeExpiredExceptions, - listId, - namespaceType, - signal, -}: ExportExceptionListProps): Promise => - http.fetch(`${EXCEPTION_LIST_URL}/_export`, { - method: 'POST', - query: { - id, - list_id: listId, - namespace_type: namespaceType, - include_expired_exceptions: includeExpiredExceptions, - }, - signal, - version, - }); - -/** - * Create a Filter query from an exception list id - * - * @param exceptionListId The id of the exception list from which create a Filter query - * @param signal AbortSignal for cancelling request - * - * @throws An error if response is not OK - */ -export const getExceptionFilterFromExceptionListIds = async ({ - alias, - chunkSize, - exceptionListIds, - excludeExceptions, - http, - signal, -}: GetExceptionFilterFromExceptionListIdsProps): Promise => - http.fetch(INTERNAL_EXCEPTION_FILTER, { - method: 'POST', - version: '1', - body: JSON.stringify({ - exception_list_ids: exceptionListIds, - type: 'exception_list_ids', - alias, - exclude_exceptions: excludeExceptions, - chunk_size: chunkSize, - }), - signal, - }); - -/** - * Create a Filter query from a list of exceptions - * - * @param exceptions Exception items to be made into a `Filter` query - * @param signal AbortSignal for cancelling request - * - * @throws An error if response is not OK - */ -export const getExceptionFilterFromExceptions = async ({ - exceptions, - alias, - excludeExceptions, - http, - chunkSize, - signal, -}: GetExceptionFilterFromExceptionsProps): Promise => - http.fetch(INTERNAL_EXCEPTION_FILTER, { - method: 'POST', - version: '1', - body: JSON.stringify({ - exceptions, - type: 'exception_items', - alias, - exclude_exceptions: excludeExceptions, - chunk_size: chunkSize, - }), - signal, - }); - -/** - * Duplicate an ExceptionList and its items by providing a ExceptionList list_id - * - * @param http Kibana http service - * @param includeExpiredExceptions boolean for including exception items with expired TTL - * @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 duplicateExceptionList = async ({ - http, - includeExpiredExceptions, - listId, - namespaceType, - signal, -}: DuplicateExceptionListProps): Promise => - http.fetch(`${EXCEPTION_LIST_URL}/_duplicate`, { - method: 'POST', - query: { - list_id: listId, - namespace_type: namespaceType, - include_expired_exceptions: includeExpiredExceptions, - }, - signal, - version, - }); diff --git a/packages/kbn-securitysolution-list-api/src/fp_utils/index.test.ts b/packages/kbn-securitysolution-list-api/src/fp_utils/index.test.ts deleted file mode 100644 index 98872f45cb77c..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/fp_utils/index.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", 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'); - }); -}); diff --git a/packages/kbn-securitysolution-list-api/src/fp_utils/index.ts b/packages/kbn-securitysolution-list-api/src/fp_utils/index.ts deleted file mode 100644 index 5614a3e7cb8df..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/fp_utils/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", 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 (taskEither: TaskEither): Promise => - 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))); diff --git a/packages/kbn-securitysolution-list-api/src/list_api/index.test.ts b/packages/kbn-securitysolution-list-api/src/list_api/index.test.ts deleted file mode 100644 index 6b8698a707aa2..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_api/index.test.ts +++ /dev/null @@ -1,445 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { createListIndex, deleteList, exportList, findLists, importList, readListIndex } from '.'; -import { - ApiPayload, - DeleteListParams, - ExportListParams, - FindListsParams, - ImportListParams, -} from '../types'; - -import { HttpFetchOptions } from '@kbn/core-http-browser'; -import { httpServiceMock } from '@kbn/core-http-browser-mocks'; - -import { getFoundListSchemaMock } from './mocks/response/found_list_schema.mock'; -import { getListResponseMock } from './mocks/response/list_schema.mock'; -import { getListItemIndexExistSchemaResponseMock } from './mocks/response/list_item_index_exist_schema.mock'; -import { getAcknowledgeSchemaResponseMock } from './mocks/response/acknowledge_schema.mock'; - -describe('Value Lists API', () => { - let httpMock: ReturnType; - - beforeEach(() => { - httpMock = httpServiceMock.createStartContract(); - }); - describe('deleteList', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue(getListResponseMock()); - }); - - it('DELETEs specifying the id as a query parameter', async () => { - const abortCtrl = new AbortController(); - const payload: ApiPayload = { - deleteReferences: false, - id: 'list-id', - ignoreReferences: true, - }; - await deleteList({ - http: httpMock, - ...payload, - signal: abortCtrl.signal, - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists', - expect.objectContaining({ - method: 'DELETE', - query: { deleteReferences: false, id: 'list-id', ignoreReferences: true }, - }) - ); - }); - - it('rejects with an error if request payload is invalid (and does not make API call)', async () => { - const abortCtrl = new AbortController(); - const payload: Omit, 'id'> & { - id: number; - } = { id: 23 }; - - await expect( - deleteList({ - http: httpMock, - ...(payload as unknown as ApiPayload), - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "23" supplied to "id"')); - expect(httpMock.fetch).not.toHaveBeenCalled(); - }); - - it('rejects with an error if response payload is invalid', async () => { - const abortCtrl = new AbortController(); - const payload: ApiPayload = { id: 'list-id' }; - const badResponse = { ...getListResponseMock(), id: undefined }; - httpMock.fetch.mockResolvedValue(badResponse); - - await expect( - deleteList({ - http: httpMock, - ...payload, - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "id"')); - }); - }); - describe('findLists', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue(getFoundListSchemaMock()); - }); - - it('GETs from the lists endpoint', async () => { - const abortCtrl = new AbortController(); - await findLists({ - http: httpMock, - pageIndex: 1, - pageSize: 10, - signal: abortCtrl.signal, - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/_find', - expect.objectContaining({ - method: 'GET', - }) - ); - }); - - it('sends pagination as query parameters', async () => { - const abortCtrl = new AbortController(); - await findLists({ - cursor: 'cursor', - http: httpMock, - pageIndex: 1, - pageSize: 10, - signal: abortCtrl.signal, - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/_find', - expect.objectContaining({ - query: { - cursor: 'cursor', - page: 1, - per_page: 10, - }, - }) - ); - }); - - it('sends sort_field and sort_order as query parameters', async () => { - const abortCtrl = new AbortController(); - await findLists({ - cursor: 'cursor', - http: httpMock, - pageIndex: 1, - pageSize: 10, - signal: abortCtrl.signal, - sortField: 'created_at', - sortOrder: 'desc', - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/_find', - expect.objectContaining({ - query: { - cursor: 'cursor', - page: 1, - per_page: 10, - sort_field: 'created_at', - sort_order: 'desc', - }, - }) - ); - }); - - it('rejects with an error if request payload is invalid (and does not make API call)', async () => { - const abortCtrl = new AbortController(); - const payload: ApiPayload = { - pageIndex: 10, - pageSize: 0, - }; - - await expect( - findLists({ - http: httpMock, - ...payload, - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "0" supplied to "per_page"')); - expect(httpMock.fetch).not.toHaveBeenCalled(); - }); - - it('rejects with an error if response payload is invalid', async () => { - const abortCtrl = new AbortController(); - const payload: ApiPayload = { - pageIndex: 1, - pageSize: 10, - }; - const badResponse = { ...getFoundListSchemaMock(), cursor: undefined }; - httpMock.fetch.mockResolvedValue(badResponse); - - await expect( - findLists({ - http: httpMock, - ...payload, - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "cursor"')); - }); - }); - describe('importList', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue(getListResponseMock()); - }); - - it('POSTs the file', async () => { - const abortCtrl = new AbortController(); - const file = new File([], 'name'); - - await importList({ - file, - http: httpMock, - listId: 'my_list', - signal: abortCtrl.signal, - type: 'keyword', - }); - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/items/_import', - expect.objectContaining({ - method: 'POST', - }) - ); - - // httpmock's fetch signature is inferred incorrectly - const [[, { body }]] = httpMock.fetch.mock.calls as unknown as Array< - [unknown, HttpFetchOptions] - >; - const actualFile = (body as FormData).get('file'); - expect(actualFile).toEqual(file); - }); - - it('sends type and id as query parameters', async () => { - const abortCtrl = new AbortController(); - const file = new File([], 'name'); - - await importList({ - file, - http: httpMock, - listId: 'my_list', - signal: abortCtrl.signal, - type: 'keyword', - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/items/_import', - expect.objectContaining({ - query: { list_id: 'my_list', type: 'keyword' }, - }) - ); - }); - - it('rejects with an error if request body is invalid (and does not make API call)', async () => { - const abortCtrl = new AbortController(); - const payload: ApiPayload = { - file: undefined as unknown as File, - listId: 'list-id', - type: 'ip', - }; - - await expect( - importList({ - http: httpMock, - ...payload, - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "file"')); - expect(httpMock.fetch).not.toHaveBeenCalled(); - }); - - it('rejects with an error if request params are invalid (and does not make API call)', async () => { - const abortCtrl = new AbortController(); - const file = new File([], 'name'); - const payload: ApiPayload = { - file, - listId: 'list-id', - type: 'other' as 'ip', - }; - - await expect( - importList({ - http: httpMock, - ...payload, - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "other" supplied to "type"')); - expect(httpMock.fetch).not.toHaveBeenCalled(); - }); - - it('rejects with an error if response payload is invalid', async () => { - const abortCtrl = new AbortController(); - const file = new File([], 'name'); - const payload: ApiPayload = { - file, - listId: 'list-id', - type: 'ip', - }; - const badResponse = { ...getListResponseMock(), id: undefined }; - httpMock.fetch.mockResolvedValue(badResponse); - - await expect( - importList({ - http: httpMock, - ...payload, - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "id"')); - }); - }); - describe('exportList', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue({}); - }); - - it('POSTs to the export endpoint', async () => { - const abortCtrl = new AbortController(); - - await exportList({ - http: httpMock, - listId: 'my_list', - signal: abortCtrl.signal, - }); - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/items/_export', - expect.objectContaining({ - method: 'POST', - }) - ); - }); - - it('sends type and id as query parameters', async () => { - const abortCtrl = new AbortController(); - - await exportList({ - http: httpMock, - listId: 'my_list', - signal: abortCtrl.signal, - }); - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/items/_export', - expect.objectContaining({ - query: { list_id: 'my_list' }, - }) - ); - }); - - it('rejects with an error if request params are invalid (and does not make API call)', async () => { - const abortCtrl = new AbortController(); - const payload: ApiPayload = { - listId: 23 as unknown as string, - }; - - await expect( - exportList({ - http: httpMock, - ...payload, - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "23" supplied to "list_id"')); - expect(httpMock.fetch).not.toHaveBeenCalled(); - }); - }); - - describe('readListIndex', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue(getListItemIndexExistSchemaResponseMock()); - }); - - it('GETs the list index', async () => { - const abortCtrl = new AbortController(); - await readListIndex({ - http: httpMock, - signal: abortCtrl.signal, - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/index', - expect.objectContaining({ - method: 'GET', - }) - ); - }); - - it('returns the response when valid', async () => { - const abortCtrl = new AbortController(); - const result = await readListIndex({ - http: httpMock, - signal: abortCtrl.signal, - }); - - expect(result).toEqual(getListItemIndexExistSchemaResponseMock()); - }); - - it('rejects with an error if response payload is invalid', async () => { - const abortCtrl = new AbortController(); - const badResponse = { ...getListItemIndexExistSchemaResponseMock(), list_index: undefined }; - httpMock.fetch.mockResolvedValue(badResponse); - - await expect( - readListIndex({ - http: httpMock, - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "list_index"')); - }); - }); - - describe('createListIndex', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue(getAcknowledgeSchemaResponseMock()); - }); - - it('GETs the list index', async () => { - const abortCtrl = new AbortController(); - await createListIndex({ - http: httpMock, - signal: abortCtrl.signal, - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/index', - expect.objectContaining({ - method: 'POST', - }) - ); - }); - - it('returns the response when valid', async () => { - const abortCtrl = new AbortController(); - const result = await createListIndex({ - http: httpMock, - signal: abortCtrl.signal, - }); - - expect(result).toEqual(getAcknowledgeSchemaResponseMock()); - }); - - it('rejects with an error if response payload is invalid', async () => { - const abortCtrl = new AbortController(); - const badResponse = { acknowledged: undefined }; - httpMock.fetch.mockResolvedValue(badResponse); - - await expect( - createListIndex({ - http: httpMock, - signal: abortCtrl.signal, - }) - ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "acknowledged"')); - }); - }); -}); diff --git a/packages/kbn-securitysolution-list-api/src/list_api/index.ts b/packages/kbn-securitysolution-list-api/src/list_api/index.ts deleted file mode 100644 index 3087ed5333cc4..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_api/index.ts +++ /dev/null @@ -1,344 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", 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, - ReadListSchema, - acknowledgeSchema, - deleteListSchema, - readListSchema, - exportListItemQuerySchema, - findListSchema, - foundListSchema, - importListItemQuerySchema, - importListItemSchema, - listItemIndexExistSchema, - listSchema, - foundListsBySizeSchema, - FoundListsBySizeSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { - LIST_INDEX, - LIST_ITEM_URL, - LIST_PRIVILEGES_URL, - LIST_URL, - INTERNAL_FIND_LISTS_BY_SIZE, -} from '@kbn/securitysolution-list-constants'; -import { toError, toPromise } from '../fp_utils'; - -import { - ApiParams, - DeleteListParams, - ExportListParams, - FindListsParams, - ImportListParams, - GetListByIdParams, -} from '../types'; - -export type { - ApiParams, - DeleteListParams, - ExportListParams, - FindListsParams, - ImportListParams, -} from '../types'; - -const version = '2023-10-31'; - -const findLists = async ({ - http, - cursor, - page, - // eslint-disable-next-line @typescript-eslint/naming-convention - per_page, - signal, - // eslint-disable-next-line @typescript-eslint/naming-convention - sort_field, - // eslint-disable-next-line @typescript-eslint/naming-convention - sort_order, -}: ApiParams & FindListSchemaEncoded): Promise => { - return http.fetch(`${LIST_URL}/_find`, { - method: 'GET', - query: { - cursor, - page, - per_page, - sort_field, - sort_order, - }, - signal, - version, - }); -}; - -const findListsWithValidation = async ({ - cursor, - http, - pageIndex, - pageSize, - signal, - sortField, - sortOrder, -}: FindListsParams): Promise => - pipe( - { - cursor: cursor != null ? cursor.toString() : undefined, - page: pageIndex != null ? pageIndex.toString() : undefined, - per_page: pageSize != null ? pageSize.toString() : undefined, - sort_field: sortField != null ? sortField.toString() : undefined, - sort_order: sortOrder, - }, - (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 findListsBySize = async ({ - http, - cursor, - page, - // eslint-disable-next-line @typescript-eslint/naming-convention - per_page, - signal, -}: ApiParams & FindListSchemaEncoded): Promise => { - return http.fetch(`${INTERNAL_FIND_LISTS_BY_SIZE}`, { - method: 'GET', - version: '1', - query: { - cursor, - page, - per_page, - }, - signal, - }); -}; - -const findListsBySizeWithValidation = async ({ - cursor, - http, - pageIndex, - pageSize, - signal, -}: FindListsParams): Promise => - 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(() => findListsBySize({ http, signal, ...payload }), toError)), - chain((response) => fromEither(validateEither(foundListsBySizeSchema, response))), - flow(toPromise) - ); - -export { findListsBySizeWithValidation as findListsBySize }; - -const importList = async ({ - file, - http, - // eslint-disable-next-line @typescript-eslint/naming-convention - list_id, - type, - signal, - refresh, -}: ApiParams & - ImportListItemSchemaEncoded & - ImportListItemQuerySchemaEncoded): Promise => { - const formData = new FormData(); - formData.append('file', file as Blob); - - return http.fetch(`${LIST_ITEM_URL}/_import`, { - body: formData, - headers: { 'Content-Type': undefined }, - method: 'POST', - query: { list_id, type, refresh }, - signal, - version, - }); -}; - -const importListWithValidation = async ({ - file, - http, - listId, - type, - signal, - refresh, -}: ImportListParams): Promise => - pipe( - { - list_id: listId, - type, - refresh, - }, - (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 => - http.fetch(LIST_URL, { - method: 'DELETE', - query: { deleteReferences, id, ignoreReferences }, - signal, - version, - }); - -const deleteListWithValidation = async ({ - deleteReferences, - http, - id, - ignoreReferences, - signal, -}: DeleteListParams): Promise => - 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 => - http.fetch(`${LIST_ITEM_URL}/_export`, { - method: 'POST', - query: { list_id }, - signal, - version, - }); - -const exportListWithValidation = async ({ - http, - listId, - signal, -}: ExportListParams): Promise => - 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 => - http.fetch(LIST_INDEX, { - method: 'GET', - signal, - version, - }); - -const readListIndexWithValidation = async ({ - http, - signal, -}: ApiParams): Promise => - 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 => - http.fetch(LIST_PRIVILEGES_URL, { - method: 'GET', - signal, - version, - }); - -const createListIndex = async ({ http, signal }: ApiParams): Promise => - http.fetch(LIST_INDEX, { - method: 'POST', - signal, - version, - }); - -const createListIndexWithValidation = async ({ - http, - signal, -}: ApiParams): Promise => - flow( - () => tryCatch(() => createListIndex({ http, signal }), toError), - chain((response) => fromEither(validateEither(acknowledgeSchema, response))), - flow(toPromise) - )(); - -export { createListIndexWithValidation as createListIndex }; - -const getListById = async ({ - http, - signal, - id, -}: ApiParams & ReadListSchema): Promise => { - return http.fetch(`${LIST_URL}`, { - method: 'GET', - query: { - id, - }, - signal, - version, - }); -}; - -const getListByIdWithValidation = async ({ - http, - signal, - id, -}: GetListByIdParams): Promise => - pipe( - { - id, - }, - (payload) => fromEither(validateEither(readListSchema, payload)), - chain((payload) => tryCatch(() => getListById({ http, signal, ...payload }), toError)), - chain((response) => fromEither(validateEither(listSchema, response))), - flow(toPromise) - ); - -export { getListByIdWithValidation as getListById }; diff --git a/packages/kbn-securitysolution-list-api/src/list_api/mocks/constants.mock.ts b/packages/kbn-securitysolution-list-api/src/list_api/mocks/constants.mock.ts deleted file mode 100644 index 3043cc70642c2..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_api/mocks/constants.mock.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export const DATE_NOW = '2020-04-20T15:25:31.830Z'; -export const USER = 'some user'; -export const ELASTIC_USER = 'elastic'; -export const NAME = 'some name'; -export const DESCRIPTION = 'some description'; -export const LIST_ID = 'some-list-id'; -export const TIE_BREAKER = '6a76b69d-80df-4ab2-8c3e-85f466b06a0e'; - -export const META = {}; -export const TYPE = 'ip'; - -export const VERSION = 1; -export const IMMUTABLE = false; diff --git a/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/acknowledge_schema.mock.ts b/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/acknowledge_schema.mock.ts deleted file mode 100644 index 788fab714e2d2..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/acknowledge_schema.mock.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { AcknowledgeSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export const getAcknowledgeSchemaResponseMock = (): AcknowledgeSchema => ({ - acknowledged: true, -}); diff --git a/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/found_list_schema.mock.ts b/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/found_list_schema.mock.ts deleted file mode 100644 index 436ddcd7a83db..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/found_list_schema.mock.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { FoundListSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { getListResponseMock } from './list_schema.mock'; - -export const getFoundListSchemaMock = (): FoundListSchema => ({ - cursor: '123', - data: [getListResponseMock()], - page: 1, - per_page: 1, - total: 1, -}); diff --git a/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_item_index_exist_schema.mock.ts b/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_item_index_exist_schema.mock.ts deleted file mode 100644 index 27a54a5fd96fc..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_item_index_exist_schema.mock.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ListItemIndexExistSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export const getListItemIndexExistSchemaResponseMock = (): ListItemIndexExistSchema => ({ - list_index: true, - list_item_index: true, -}); diff --git a/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_schema.mock.ts b/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_schema.mock.ts deleted file mode 100644 index 79ed256419770..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_schema.mock.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ListSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { - DATE_NOW, - DESCRIPTION, - ELASTIC_USER, - IMMUTABLE, - LIST_ID, - META, - NAME, - TIE_BREAKER, - TYPE, - USER, - VERSION, -} from '../constants.mock'; - -export const getListResponseMock = (): ListSchema => ({ - '@timestamp': DATE_NOW, - _version: undefined, - created_at: DATE_NOW, - created_by: USER, - description: DESCRIPTION, - deserializer: undefined, - id: LIST_ID, - immutable: IMMUTABLE, - meta: META, - name: NAME, - serializer: undefined, - tie_breaker_id: TIE_BREAKER, - type: TYPE, - updated_at: DATE_NOW, - updated_by: USER, - version: VERSION, -}); - -/** - * This is useful for end to end tests where we remove the auto generated parts for comparisons - * such as created_at, updated_at, and id. - */ -export const getListResponseMockWithoutAutoGeneratedValues = (): Partial => ({ - created_by: ELASTIC_USER, - description: DESCRIPTION, - immutable: IMMUTABLE, - name: NAME, - type: TYPE, - updated_by: ELASTIC_USER, - version: VERSION, -}); diff --git a/packages/kbn-securitysolution-list-api/src/list_item_api/index.test.ts b/packages/kbn-securitysolution-list-api/src/list_item_api/index.test.ts deleted file mode 100644 index 95e37ec434107..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_item_api/index.test.ts +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { createListItem, deleteListItem, findListItems, patchListItem } from '.'; -import { httpServiceMock } from '@kbn/core-http-browser-mocks'; -import { - getFoundListSchemaMock, - getCreateListItemResponseMock, - getUpdatedListItemResponseMock, - getDeletedListItemResponseMock, -} from './mocks/response'; - -describe('Value list item API', () => { - let httpMock: ReturnType; - beforeEach(() => { - httpMock = httpServiceMock.createStartContract(); - }); - - describe('findListItems', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue(getFoundListSchemaMock()); - }); - - it('GETs from the lists endpoint with query params', async () => { - const abortCtrl = new AbortController(); - await findListItems({ - http: httpMock, - pageIndex: 1, - pageSize: 10, - signal: abortCtrl.signal, - filter: '*:*', - listId: 'list_id', - sortField: 'updated_at', - sortOrder: 'asc', - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/items/_find', - expect.objectContaining({ - method: 'GET', - query: { - cursor: undefined, - filter: '*:*', - list_id: 'list_id', - page: 1, - per_page: 10, - sort_field: 'updated_at', - sort_order: 'asc', - }, - }) - ); - }); - }); - - describe('createListItem', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue(getCreateListItemResponseMock()); - }); - - it('POSTs to the lists endpoint with the list item', async () => { - const abortCtrl = new AbortController(); - await createListItem({ - http: httpMock, - signal: abortCtrl.signal, - value: '123', - listId: 'list_id', - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/items', - expect.objectContaining({ - method: 'POST', - body: JSON.stringify({ - value: '123', - list_id: 'list_id', - }), - }) - ); - }); - - it('returns the created list item', async () => { - const abortCtrl = new AbortController(); - const result = await createListItem({ - http: httpMock, - signal: abortCtrl.signal, - value: '123', - listId: 'list_id', - }); - - expect(result).toEqual(getCreateListItemResponseMock()); - }); - }); - - describe('patchListItem', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue(getUpdatedListItemResponseMock()); - }); - - it('PATCH to the lists endpoint with the list item', async () => { - const abortCtrl = new AbortController(); - await patchListItem({ - http: httpMock, - signal: abortCtrl.signal, - id: 'item_id', - value: '123', - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/items', - expect.objectContaining({ - method: 'PATCH', - body: JSON.stringify({ - id: 'item_id', - value: '123', - }), - }) - ); - }); - - it('returns the updated list item', async () => { - const abortCtrl = new AbortController(); - const result = await patchListItem({ - http: httpMock, - signal: abortCtrl.signal, - id: 'item_id', - value: '123', - }); - - expect(result).toEqual(getUpdatedListItemResponseMock()); - }); - }); - - describe('deleteListItem', () => { - beforeEach(() => { - httpMock.fetch.mockResolvedValue(getCreateListItemResponseMock()); - }); - - it('DELETE to the lists endpoint with the list item', async () => { - const abortCtrl = new AbortController(); - await deleteListItem({ - http: httpMock, - signal: abortCtrl.signal, - id: 'item_id', - refresh: 'true', - }); - - expect(httpMock.fetch).toHaveBeenCalledWith( - '/api/lists/items', - expect.objectContaining({ - method: 'DELETE', - query: { id: 'item_id', refresh: 'true' }, - }) - ); - }); - - it('returns the deleted list item', async () => { - const abortCtrl = new AbortController(); - const result = await deleteListItem({ - http: httpMock, - signal: abortCtrl.signal, - id: 'item_id', - }); - - expect(result).toEqual(getDeletedListItemResponseMock()); - }); - }); -}); diff --git a/packages/kbn-securitysolution-list-api/src/list_item_api/index.ts b/packages/kbn-securitysolution-list-api/src/list_item_api/index.ts deleted file mode 100644 index 8c6cdc358f70a..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_item_api/index.ts +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - FindListItemSchema, - ListItemSchema, - deleteListItemSchema, - patchListItemSchema, - createListItemSchema, - findListItemSchema, - foundListItemSchema, - listItemSchema, - FoundListItemSchema, - DeleteListItemSchema, - PatchListItemSchema, - CreateListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { chain, fromEither, 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 { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; -import { - ApiParams, - FindListItemsParams, - DeleteListItemParams, - PatchListItemParams, - CreateListItemParams, -} from '../types'; -import { toError, toPromise } from '../fp_utils'; - -const version = '2023-10-31'; - -/** - * Fetch list items - */ -const findListItems = async ({ - http, - cursor, - page, - // eslint-disable-next-line @typescript-eslint/naming-convention - list_id, - // eslint-disable-next-line @typescript-eslint/naming-convention - per_page, - signal, - // eslint-disable-next-line @typescript-eslint/naming-convention - sort_field, - // eslint-disable-next-line @typescript-eslint/naming-convention - sort_order, - filter, -}: ApiParams & FindListItemSchema): Promise => { - return http.fetch(`${LIST_ITEM_URL}/_find`, { - method: 'GET', - query: { - cursor, - page, - per_page, - sort_field, - sort_order, - list_id, - filter, - }, - signal, - version, - }); -}; - -const findListItemsWithValidation = async ({ - cursor, - http, - pageIndex, - pageSize, - signal, - sortField, - sortOrder, - filter, - listId, -}: FindListItemsParams): Promise => - pipe( - { - cursor: cursor != null ? cursor.toString() : undefined, - page: pageIndex != null ? pageIndex.toString() : undefined, - per_page: pageSize != null ? pageSize.toString() : undefined, - sort_field: sortField != null ? sortField.toString() : undefined, - filter: filter != null ? filter.toString() : undefined, - sort_order: sortOrder, - list_id: listId, - }, - (payload) => fromEither(validateEither(findListItemSchema, payload)), - chain((payload) => tryCatch(() => findListItems({ http, signal, ...payload }), toError)), - chain((response) => fromEither(validateEither(foundListItemSchema, response))), - flow(toPromise) - ); - -export { findListItemsWithValidation as findListItems }; - -const deleteListItem = async ({ - http, - id, - signal, - refresh, -}: ApiParams & DeleteListItemSchema): Promise => - http.fetch(LIST_ITEM_URL, { - method: 'DELETE', - query: { id, refresh }, - signal, - version, - }); - -const deleteListItemWithValidation = async ({ - http, - id, - signal, - refresh, -}: DeleteListItemParams): Promise => - pipe( - { id, refresh }, - (payload) => fromEither(validateEither(deleteListItemSchema, payload)), - chain((payload) => - tryCatch( - () => - deleteListItem({ - http, - signal, - ...payload, - value: undefined, - list_id: undefined, - }), - toError - ) - ), - chain((response) => fromEither(validateEither(listItemSchema, response))), - flow(toPromise) - ); - -export { deleteListItemWithValidation as deleteListItem }; - -const patchListItem = async ({ - http, - id, - signal, - value, - _version, -}: ApiParams & PatchListItemSchema): Promise => - http.fetch(LIST_ITEM_URL, { - method: 'PATCH', - body: JSON.stringify({ id, value, _version }), - signal, - version, - }); - -const patchListItemWithValidation = async ({ - http, - id, - signal, - value, - refresh, - _version, -}: PatchListItemParams): Promise => - pipe( - { id, value, _version, refresh }, - (payload) => fromEither(validateEither(patchListItemSchema, payload)), - chain((payload) => - tryCatch( - () => - patchListItem({ - http, - signal, - ...payload, - }), - toError - ) - ), - chain((response) => fromEither(validateEither(listItemSchema, response))), - flow(toPromise) - ); - -export { patchListItemWithValidation as patchListItem }; - -const createListItem = async ({ - http, - signal, - value, - // eslint-disable-next-line @typescript-eslint/naming-convention - list_id, - refresh, -}: ApiParams & CreateListItemSchema): Promise => - http.fetch(LIST_ITEM_URL, { - method: 'POST', - body: JSON.stringify({ value, list_id, refresh }), - signal, - version, - }); - -const createListItemWithValidation = async ({ - http, - signal, - value, - refresh, - listId, -}: CreateListItemParams): Promise => - pipe( - { list_id: listId, value, refresh }, - (payload) => fromEither(validateEither(createListItemSchema, payload)), - chain((payload) => - tryCatch( - () => - createListItem({ - http, - signal, - ...payload, - }), - toError - ) - ), - chain((response) => fromEither(validateEither(listItemSchema, response))), - flow(toPromise) - ); - -export { createListItemWithValidation as createListItem }; diff --git a/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/index.ts b/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/index.ts deleted file mode 100644 index 5ef4e52adbe88..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { FoundListItemSchema, ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { getListItemResponseMock } from './list_item_schema.mock'; - -export const getFoundListSchemaMock = (): FoundListItemSchema => ({ - cursor: '123', - data: [getListItemResponseMock()], - page: 1, - per_page: 1, - total: 1, -}); - -export const getCreateListItemResponseMock = (): ListItemSchema => getListItemResponseMock(); -export const getUpdatedListItemResponseMock = (): ListItemSchema => getListItemResponseMock(); -export const getDeletedListItemResponseMock = (): ListItemSchema => getListItemResponseMock(); diff --git a/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/list_item_schema.mock.ts b/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/list_item_schema.mock.ts deleted file mode 100644 index eb67b97773548..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/list_item_schema.mock.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export const getListItemResponseMock = (): ListItemSchema => ({ - _version: '1', - '@timestamp': '2020-08-11T11:22:13.670Z', - created_at: '2020-08-11T11:22:13.670Z', - created_by: 'elastic', - deserializer: 'some deserializer', - id: 'bpdB3XMBx7pemMHopQ6M', - list_id: 'list_id', - meta: {}, - serializer: 'some serializer', - tie_breaker_id: '17d3befb-dc22-4b3c-a286-b5504c4fbeeb', - type: 'keyword', - updated_at: '2020-08-11T11:22:13.670Z', - updated_by: 'elastic', - value: 'some keyword', -}); diff --git a/packages/kbn-securitysolution-list-api/src/types.ts b/packages/kbn-securitysolution-list-api/src/types.ts deleted file mode 100644 index c78071bb5824f..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/types.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { - SortFieldOrUndefined, - SortOrderOrUndefined, - Type, - Refresh, - RefreshWithWaitFor, -} 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: (...args: any) => any; -} - -export interface ApiParams { - http: HttpStart; - signal: AbortSignal; -} -export type ApiPayload = Omit; - -export interface FindListsParams extends ApiParams { - cursor?: string | undefined; - pageSize: number | undefined; - pageIndex: number | undefined; - sortOrder?: SortOrderOrUndefined; - sortField?: SortFieldOrUndefined; -} - -export interface FindListItemsParams extends ApiParams { - cursor?: string | undefined; - pageSize: number | undefined; - pageIndex: number | undefined; - sortOrder?: SortOrderOrUndefined; - sortField?: SortFieldOrUndefined; - filter: string | undefined; - listId: string; -} - -export interface ImportListParams extends ApiParams { - file: File; - listId: string | undefined; - type: Type | undefined; - refresh?: RefreshWithWaitFor; -} - -export interface DeleteListParams extends ApiParams { - deleteReferences?: boolean; - id: string; - ignoreReferences?: boolean; -} - -export interface DeleteListItemParams extends ApiParams { - refresh?: Refresh; - id: string; -} - -export interface PatchListItemParams extends ApiParams { - refresh?: Refresh; - id: string; - value: string; - _version?: string; -} - -export interface CreateListItemParams extends ApiParams { - refresh?: RefreshWithWaitFor; - value: string; - listId: string; -} - -export interface ExportListParams extends ApiParams { - listId: string; -} - -export interface GetListByIdParams extends ApiParams { - id: string; -} diff --git a/packages/kbn-securitysolution-list-api/tsconfig.json b/packages/kbn-securitysolution-list-api/tsconfig.json deleted file mode 100644 index 2c2ca29316fcd..0000000000000 --- a/packages/kbn-securitysolution-list-api/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/securitysolution-io-ts-list-types", - "@kbn/securitysolution-io-ts-utils", - "@kbn/securitysolution-list-constants", - "@kbn/core-http-browser", - "@kbn/core-http-browser-mocks", - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-list-constants/index.ts b/packages/kbn-securitysolution-list-constants/index.ts deleted file mode 100644 index 6f1e8d01b830a..0000000000000 --- a/packages/kbn-securitysolution-list-constants/index.ts +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { deepFreeze } from '@kbn/std'; - -/** - * Value list routes - */ -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`; - -/** - * Internal value list routes - */ -export const INTERNAL_LIST_URL = '/internal/lists'; -export const INTERNAL_FIND_LISTS_BY_SIZE = `${INTERNAL_LIST_URL}/_find_lists_by_size` as const; -export const INTERNAL_EXCEPTION_FILTER = `${INTERNAL_LIST_URL}/_create_filter` as const; - -/** - * Exception list routes - */ -export const EXCEPTION_LIST_URL = '/api/exception_lists'; -export const EXCEPTION_LIST_ITEM_URL = '/api/exception_lists/items'; - -/** - * Internal exception list routes - */ -export const INTERNAL_EXCEPTION_LIST_URL = `/internal${EXCEPTION_LIST_URL}`; -export const INTERNAL_EXCEPTIONS_LIST_ENSURE_CREATED_URL = `${INTERNAL_EXCEPTION_LIST_URL}/_create`; - -/** - * 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'; - -/** - * This ID is used for _both_ the Saved Object ID and for the list_id - * for the single global space agnostic endpoint list - */ -export const ENDPOINT_LIST_ID = 'endpoint_list'; - -/** The name of the single global space agnostic endpoint list */ -export const ENDPOINT_LIST_NAME = 'Endpoint Security Exception List'; - -/** The description of the single global space agnostic endpoint list */ -export const ENDPOINT_LIST_DESCRIPTION = 'Endpoint Security Exception List'; - -export const MAX_EXCEPTION_LIST_SIZE = 10000; - -export const MAXIMUM_SMALL_VALUE_LIST_SIZE = 65536; - -export const MAXIMUM_SMALL_IP_RANGE_VALUE_LIST_DASH_SIZE = 200; - -/** - * List definitions for Endpoint Artifact - */ -export const ENDPOINT_ARTIFACT_LISTS = deepFreeze({ - trustedApps: { - id: 'endpoint_trusted_apps', - name: 'Endpoint Security Trusted Apps List', - description: 'Endpoint Security Trusted Apps List', - }, - eventFilters: { - id: 'endpoint_event_filters', - name: 'Endpoint Security Event Filters List', - description: 'Endpoint Security Event Filters List', - }, - hostIsolationExceptions: { - id: 'endpoint_host_isolation_exceptions', - name: 'Endpoint Security Host isolation exceptions List', - description: 'Endpoint Security Host isolation exceptions List', - }, - blocklists: { - id: 'endpoint_blocklists', - name: 'Endpoint Security Blocklists List', - description: 'Endpoint Security Blocklists List', - }, -}); - -/** - * The IDs of all Endpoint artifact lists - */ -export const ENDPOINT_ARTIFACT_LIST_IDS = Object.freeze( - Object.values(ENDPOINT_ARTIFACT_LISTS).map(({ id }) => id) -); - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_TRUSTED_APPS_LIST_ID = ENDPOINT_ARTIFACT_LISTS.trustedApps.id; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_TRUSTED_APPS_LIST_NAME = ENDPOINT_ARTIFACT_LISTS.trustedApps.name; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION = - ENDPOINT_ARTIFACT_LISTS.trustedApps.description; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_EVENT_FILTERS_LIST_ID = ENDPOINT_ARTIFACT_LISTS.eventFilters.id; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_EVENT_FILTERS_LIST_NAME = ENDPOINT_ARTIFACT_LISTS.eventFilters.name; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION = - ENDPOINT_ARTIFACT_LISTS.eventFilters.description; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID = - ENDPOINT_ARTIFACT_LISTS.hostIsolationExceptions.id; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_NAME = - ENDPOINT_ARTIFACT_LISTS.hostIsolationExceptions.name; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_DESCRIPTION = - ENDPOINT_ARTIFACT_LISTS.hostIsolationExceptions.description; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_BLOCKLISTS_LIST_ID = ENDPOINT_ARTIFACT_LISTS.blocklists.id; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_BLOCKLISTS_LIST_NAME = ENDPOINT_ARTIFACT_LISTS.blocklists.name; - -/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ -export const ENDPOINT_BLOCKLISTS_LIST_DESCRIPTION = ENDPOINT_ARTIFACT_LISTS.blocklists.description; diff --git a/packages/kbn-securitysolution-list-constants/package.json b/packages/kbn-securitysolution-list-constants/package.json deleted file mode 100644 index 1b03f95f0f150..0000000000000 --- a/packages/kbn-securitysolution-list-constants/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/securitysolution-list-constants", - "version": "1.0.0", - "description": "security solution list constants to use across plugins such lists, security_solution, cases, etc...", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-list-constants/tsconfig.json b/packages/kbn-securitysolution-list-constants/tsconfig.json deleted file mode 100644 index 0cd8de173ed4f..0000000000000 --- a/packages/kbn-securitysolution-list-constants/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/std" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-list-hooks/index.ts b/packages/kbn-securitysolution-list-hooks/index.ts deleted file mode 100644 index 5ec2cb85d8c23..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './src/transforms'; -export * from './src/use_api'; -export * from './src/use_create_list_index'; -export * from './src/use_cursor'; -export * from './src/use_delete_list'; -export * from './src/use_exception_lists'; -export * from './src/use_export_list'; -export * from './src/use_find_lists'; -export * from './src/use_find_lists_by_size'; -export * from './src/use_import_list'; -export * from './src/use_persist_exception_item'; -export * from './src/use_persist_exception_list'; -export * from './src/use_read_list_index'; -export * from './src/use_read_list_privileges'; -export * from './src/use_find_list_items'; -export * from './src/use_create_list_item'; -export * from './src/use_delete_list_item'; -export * from './src/use_patch_list_item'; -export * from './src/use_get_list_by_id'; diff --git a/packages/kbn-securitysolution-list-hooks/jest.config.js b/packages/kbn-securitysolution-list-hooks/jest.config.js deleted file mode 100644 index f5fadd8bf399a..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-list-hooks'], -}; diff --git a/packages/kbn-securitysolution-list-hooks/package.json b/packages/kbn-securitysolution-list-hooks/package.json deleted file mode 100644 index 3d9f2019d3f23..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@kbn/securitysolution-list-hooks", - "version": "1.0.0", - "description": "Security solution list ReactJS hooks", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true, - "sideEffects": false -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-list-hooks/src/constants.ts b/packages/kbn-securitysolution-list-hooks/src/constants.ts deleted file mode 100644 index 333fb40ca4caf..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/constants.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export const READ_INDEX_QUERY_KEY = ['detectionEngine', 'listIndex']; diff --git a/packages/kbn-securitysolution-list-hooks/src/index.ts b/packages/kbn-securitysolution-list-hooks/src/index.ts deleted file mode 100644 index 852d138b8931d..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './transforms'; -export * from './use_api'; -export * from './use_create_list_index'; -export * from './use_cursor'; -export * from './use_delete_list'; -export * from './use_exception_lists'; -export * from './use_export_list'; -export * from './use_find_lists'; -export * from './use_import_list'; -export * from './use_persist_exception_item'; -export * from './use_persist_exception_list'; -export * from './use_read_list_index'; -export * from './use_read_list_privileges'; -export * from './use_find_list_items'; -export * from './use_create_list_item'; -export * from './use_delete_list_item'; -export * from './use_patch_list_item'; -export * from './use_get_list_by_id'; diff --git a/packages/kbn-securitysolution-list-hooks/src/mocks/constants.mock.ts b/packages/kbn-securitysolution-list-hooks/src/mocks/constants.mock.ts deleted file mode 100644 index 67dcac046c8d2..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/mocks/constants.mock.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - CommentsArray, - EntriesArray, - Entry, - EntryMatch, - EntryNested, - OsTypeArray, -} from '@kbn/securitysolution-io-ts-list-types'; - -export const DATE_NOW = '2020-04-20T15:25:31.830Z'; -export const USER = 'some user'; -export const ELASTIC_USER = 'elastic'; -export const NAME = 'some name'; -export const DESCRIPTION = 'some description'; -export const LIST_ID = 'some-list-id'; -export const TIE_BREAKER = '6a76b69d-80df-4ab2-8c3e-85f466b06a0e'; - -export const META = {}; -export const TYPE = 'ip'; - -export const VERSION = 1; -export const IMMUTABLE = false; -// Exception List specific -export const ID = 'uuid_here'; -export const NAMESPACE_TYPE = 'single'; -export const OS_TYPES: OsTypeArray = ['windows']; -export const TAGS = []; -export const UPDATED_COMMENTS = [ - { - comment: 'old comment', - id: 'old_created_id', - }, - { - comment: 'new comment', - id: 'new_id', - }, -]; -export const COMMENTS = []; -export const ENTRIES: EntriesArray = [ - { - entries: [{ field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }], - field: 'some.parentField', - type: 'nested', - }, - { field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' }, -]; -export const ITEM_ID = 'some-list-item-id'; -export const ITEM_TYPE = 'simple'; -export const LIST_ITEM_ID = 'some-list-item-id'; -// ENTRIES_WITH_IDS should only be used to mock out functionality of a collection of transforms -// that are UI specific and useful for UI concerns that are inserted between the -// API and the actual user interface. In some ways these might be viewed as -// technical debt or to compensate for the differences and preferences -// of how ReactJS might prefer data vs. how we want to model data. -export const ENTRIES_WITH_IDS: EntriesArray = [ - { - entries: [ - { - field: 'nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as EntryMatch & { id: string }, - ], - field: 'some.parentField', - id: '123', - type: 'nested', - } as EntryNested & { id: string }, - { - field: 'some.not.nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as Entry & { id: string }, -]; - -export const COMMENTS_WITH_CREATEDAT_CREATEDBY: CommentsArray = [ - { - comment: 'old comment', - id: 'old_created_id', - created_at: '2022-01-08T15:25:31.830Z', - created_by: 'elastic', - }, - { - comment: 'new comment', - id: 'new_id', - created_at: '2022-05-14T15:25:31.830Z', - created_by: 'elastic', - }, -]; diff --git a/packages/kbn-securitysolution-list-hooks/src/mocks/request/update_exception_list_item_schema.mock.ts b/packages/kbn-securitysolution-list-hooks/src/mocks/request/update_exception_list_item_schema.mock.ts deleted file mode 100644 index 916ce0c81daca..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/mocks/request/update_exception_list_item_schema.mock.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { UpdateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { - DESCRIPTION, - ENTRIES, - ID, - ITEM_ID, - ITEM_TYPE, - LIST_ITEM_ID, - META, - NAME, - NAMESPACE_TYPE, - OS_TYPES, - TAGS, - UPDATED_COMMENTS, -} from '../constants.mock'; - -export const getUpdateExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({ - _version: undefined, - comments: UPDATED_COMMENTS, - description: DESCRIPTION, - entries: ENTRIES, - id: ID, - item_id: LIST_ITEM_ID, - meta: META, - name: NAME, - namespace_type: NAMESPACE_TYPE, - os_types: ['linux'], - tags: TAGS, - type: ITEM_TYPE, -}); - -/** - * Useful for end to end tests and other mechanisms which want to fill in the values - * after doing a get of the structure. - */ -export const getUpdateMinimalExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({ - description: DESCRIPTION, - entries: ENTRIES, - item_id: ITEM_ID, - name: NAME, - os_types: OS_TYPES, - type: ITEM_TYPE, -}); diff --git a/packages/kbn-securitysolution-list-hooks/src/mocks/response/exception_list_item_schema.mock.ts b/packages/kbn-securitysolution-list-hooks/src/mocks/response/exception_list_item_schema.mock.ts deleted file mode 100644 index 0c5e732a1f301..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/mocks/response/exception_list_item_schema.mock.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { - COMMENTS, - DATE_NOW, - DESCRIPTION, - ELASTIC_USER, - ENTRIES, - ITEM_ID, - ITEM_TYPE, - LIST_ID, - META, - NAME, - NAMESPACE_TYPE, - OS_TYPES, - TIE_BREAKER, - USER, -} from '../constants.mock'; - -export const getExceptionListItemSchemaMock = ( - overrides?: Partial -): ExceptionListItemSchema => ({ - _version: undefined, - comments: COMMENTS, - created_at: DATE_NOW, - created_by: USER, - description: DESCRIPTION, - entries: ENTRIES, - expire_time: undefined, - id: '1', - item_id: 'endpoint_list_item', - list_id: 'endpoint_list_id', - meta: META, - name: NAME, - namespace_type: NAMESPACE_TYPE, - os_types: [], - tags: ['user added string for a tag', 'malware'], - tie_breaker_id: TIE_BREAKER, - type: ITEM_TYPE, - updated_at: DATE_NOW, - updated_by: USER, - ...(overrides || {}), -}); - -/** - * This is useful for end to end tests where we remove the auto generated parts for comparisons - * such as created_at, updated_at, and id. - */ -export const getExceptionListItemResponseMockWithoutAutoGeneratedValues = - (): Partial => ({ - comments: [], - created_by: ELASTIC_USER, - description: DESCRIPTION, - entries: ENTRIES, - item_id: ITEM_ID, - list_id: LIST_ID, - name: NAME, - namespace_type: 'single', - os_types: OS_TYPES, - tags: [], - type: ITEM_TYPE, - updated_by: ELASTIC_USER, - }); diff --git a/packages/kbn-securitysolution-list-hooks/src/mocks/response/found_list_schema.mock.ts b/packages/kbn-securitysolution-list-hooks/src/mocks/response/found_list_schema.mock.ts deleted file mode 100644 index 436ddcd7a83db..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/mocks/response/found_list_schema.mock.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { FoundListSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { getListResponseMock } from './list_schema.mock'; - -export const getFoundListSchemaMock = (): FoundListSchema => ({ - cursor: '123', - data: [getListResponseMock()], - page: 1, - per_page: 1, - total: 1, -}); diff --git a/packages/kbn-securitysolution-list-hooks/src/mocks/response/list_schema.mock.ts b/packages/kbn-securitysolution-list-hooks/src/mocks/response/list_schema.mock.ts deleted file mode 100644 index 79ed256419770..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/mocks/response/list_schema.mock.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { ListSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { - DATE_NOW, - DESCRIPTION, - ELASTIC_USER, - IMMUTABLE, - LIST_ID, - META, - NAME, - TIE_BREAKER, - TYPE, - USER, - VERSION, -} from '../constants.mock'; - -export const getListResponseMock = (): ListSchema => ({ - '@timestamp': DATE_NOW, - _version: undefined, - created_at: DATE_NOW, - created_by: USER, - description: DESCRIPTION, - deserializer: undefined, - id: LIST_ID, - immutable: IMMUTABLE, - meta: META, - name: NAME, - serializer: undefined, - tie_breaker_id: TIE_BREAKER, - type: TYPE, - updated_at: DATE_NOW, - updated_by: USER, - version: VERSION, -}); - -/** - * This is useful for end to end tests where we remove the auto generated parts for comparisons - * such as created_at, updated_at, and id. - */ -export const getListResponseMockWithoutAutoGeneratedValues = (): Partial => ({ - created_by: ELASTIC_USER, - description: DESCRIPTION, - immutable: IMMUTABLE, - name: NAME, - type: TYPE, - updated_by: ELASTIC_USER, - version: VERSION, -}); diff --git a/packages/kbn-securitysolution-list-hooks/src/transforms/index.test.ts b/packages/kbn-securitysolution-list-hooks/src/transforms/index.test.ts deleted file mode 100644 index bb0cb6e6e9075..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/transforms/index.test.ts +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { - CreateExceptionListItemSchema, - Entry, - EntryMatch, - EntryNested, - ExceptionListItemSchema, - UpdateExceptionListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { - addIdToExceptionItemEntries, - removeIdFromExceptionItemsEntries, - transformInput, - transformOutput, -} from '../..'; - -import { getCreateExceptionListItemSchemaMock } from '../mocks/request/create_exception_list_item_schema.mock'; -import { getUpdateExceptionListItemSchemaMock } from '../mocks/request/update_exception_list_item_schema.mock'; -import { getExceptionListItemSchemaMock } from '../mocks/response/exception_list_item_schema.mock'; -import { COMMENTS_WITH_CREATEDAT_CREATEDBY, ENTRIES_WITH_IDS } from '../mocks/constants.mock'; - -jest.mock('uuid', () => ({ - v4: jest.fn().mockReturnValue('123'), -})); - -describe('Exceptions transforms', () => { - describe('transformOutput', () => { - it('should return same output as input with stripped ids per entry - CreateExceptionListItemSchema', () => { - const mockCreateExceptionItem = { - ...getCreateExceptionListItemSchemaMock(), - entries: ENTRIES_WITH_IDS, - }; - const output = transformOutput(mockCreateExceptionItem); - const expectedOutput: CreateExceptionListItemSchema = getCreateExceptionListItemSchemaMock(); - - expect(output).toEqual(expectedOutput); - }); - - it('should return same output as input with stripped ids per entry - UpdateExceptionListItemSchema', () => { - const mockUpdateExceptionItem = { - ...getUpdateExceptionListItemSchemaMock(), - entries: ENTRIES_WITH_IDS, - }; - const output = transformOutput(mockUpdateExceptionItem); - const expectedOutput: UpdateExceptionListItemSchema = getUpdateExceptionListItemSchemaMock(); - - expect(output).toEqual(expectedOutput); - }); - it('should return output as input with stripped createdAt and createdBy per entry - UpdateExceptionListItemSchema', () => { - const mockUpdateExceptionItem = { - ...getUpdateExceptionListItemSchemaMock(), - entries: ENTRIES_WITH_IDS, - comments: COMMENTS_WITH_CREATEDAT_CREATEDBY, - }; - const output = transformOutput(mockUpdateExceptionItem); - const expectedOutput: UpdateExceptionListItemSchema = getUpdateExceptionListItemSchemaMock(); - - expect(output).toEqual(expectedOutput); - }); - }); - - describe('transformInput', () => { - it('should return same output as input with added ids per entry', () => { - const mockExceptionItem = getExceptionListItemSchemaMock(); - const output = transformInput(mockExceptionItem); - const expectedOutput: ExceptionListItemSchema = { - ...getExceptionListItemSchemaMock(), - entries: ENTRIES_WITH_IDS, - }; - - expect(output).toEqual(expectedOutput); - }); - }); - - describe('addIdToExceptionItemEntries', () => { - it('should return same output as input with added ids per entry', () => { - const mockExceptionItem: ExceptionListItemSchema = { - ...getExceptionListItemSchemaMock(), - entries: [ - { - field: 'some.not.nested.field', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - }; - const output = addIdToExceptionItemEntries(mockExceptionItem); - const expectedOutput: ExceptionListItemSchema = { - ...getExceptionListItemSchemaMock(), - entries: [ - { - field: 'some.not.nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as Entry & { id: string }, - ], - }; - - expect(output).toEqual(expectedOutput); - }); - - it('should return same output as input with added ids per nested entry', () => { - const mockExceptionItem: ExceptionListItemSchema = { - ...getExceptionListItemSchemaMock(), - entries: [ - { - entries: [ - { - field: 'nested.field', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - field: 'some.parentField', - type: 'nested', - }, - ], - }; - const output = addIdToExceptionItemEntries(mockExceptionItem); - const expectedOutput: ExceptionListItemSchema = { - ...getExceptionListItemSchemaMock(), - entries: [ - { - entries: [ - { - field: 'nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as EntryMatch & { id: string }, - ], - field: 'some.parentField', - id: '123', - type: 'nested', - } as EntryNested & { id: string }, - ], - }; - - expect(output).toEqual(expectedOutput); - }); - }); - - describe('removeIdFromExceptionItemsEntries', () => { - it('should return same output as input with stripped ids per entry - CreateExceptionListItemSchema', () => { - const mockCreateExceptionItem = { - ...getCreateExceptionListItemSchemaMock(), - entries: [ - { - field: 'some.not.nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as Entry & { id: string }, - ], - }; - const output = removeIdFromExceptionItemsEntries(mockCreateExceptionItem); - const expectedOutput: CreateExceptionListItemSchema = { - ...getCreateExceptionListItemSchemaMock(), - entries: [ - { - field: 'some.not.nested.field', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - }; - - expect(output).toEqual(expectedOutput); - }); - - it('should return same output as input with stripped ids per nested entry - CreateExceptionListItemSchema', () => { - const mockCreateExceptionItem = { - ...getCreateExceptionListItemSchemaMock(), - entries: [ - { - entries: [ - { - field: 'nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as EntryMatch & { id: string }, - ], - field: 'some.parentField', - id: '123', - type: 'nested', - } as EntryNested & { id: string }, - ], - }; - const output = removeIdFromExceptionItemsEntries(mockCreateExceptionItem); - const expectedOutput: CreateExceptionListItemSchema = { - ...getCreateExceptionListItemSchemaMock(), - entries: [ - { - entries: [ - { - field: 'nested.field', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - field: 'some.parentField', - type: 'nested', - }, - ], - }; - - expect(output).toEqual(expectedOutput); - }); - - it('should return same output as input with stripped ids per entry - UpdateExceptionListItemSchema', () => { - const mockUpdateExceptionItem = { - ...getUpdateExceptionListItemSchemaMock(), - entries: [ - { - field: 'some.not.nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as Entry & { id: string }, - ], - }; - const output = removeIdFromExceptionItemsEntries(mockUpdateExceptionItem); - const expectedOutput: UpdateExceptionListItemSchema = { - ...getUpdateExceptionListItemSchemaMock(), - entries: [ - { - field: 'some.not.nested.field', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - }; - - expect(output).toEqual(expectedOutput); - }); - - it('should return same output as input with stripped ids per nested entry - UpdateExceptionListItemSchema', () => { - const mockUpdateExceptionItem = { - ...getUpdateExceptionListItemSchemaMock(), - entries: [ - { - entries: [ - { - field: 'nested.field', - id: '123', - operator: 'included', - type: 'match', - value: 'some value', - } as EntryMatch & { id: string }, - ], - field: 'some.parentField', - id: '123', - type: 'nested', - } as EntryNested & { id: string }, - ], - }; - const output = removeIdFromExceptionItemsEntries(mockUpdateExceptionItem); - const expectedOutput: UpdateExceptionListItemSchema = { - ...getUpdateExceptionListItemSchemaMock(), - entries: [ - { - entries: [ - { - field: 'nested.field', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - field: 'some.parentField', - type: 'nested', - }, - ], - }; - - expect(output).toEqual(expectedOutput); - }); - }); -}); diff --git a/packages/kbn-securitysolution-list-hooks/src/transforms/index.ts b/packages/kbn-securitysolution-list-hooks/src/transforms/index.ts deleted file mode 100644 index c30ea9ad8679c..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/transforms/index.ts +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { flow } from 'fp-ts/lib/function'; -import { addIdToItem, removeIdFromItem } from '@kbn/securitysolution-utils'; -import type { - CreateExceptionListItemSchema, - EntriesArray, - Entry, - ExceptionListItemSchema, - UpdateExceptionListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; - -// These are a collection of transforms that are UI specific and useful for UI concerns -// that are inserted between the API and the actual user interface. In some ways these -// might be viewed as technical debt or to compensate for the differences and preferences -// of how ReactJS might prefer data vs. how we want to model data. Each function should have -// a description giving context around the transform. - -/** - * Transforms the output of exception items to compensate for technical debt or UI concerns such as - * ReactJS preferences for having ids within arrays if the data is not modeled that way. - * - * If you add a new transform of the output called "myNewTransform" do it - * in the form of: - * flow(removeIdFromExceptionItemsEntries, myNewTransform)(exceptionItem) - * - * @param exceptionItem The exceptionItem to transform the output of - * @returns The exceptionItem transformed from the output - */ -export const transformOutput = ( - exceptionItem: UpdateExceptionListItemSchema | ExceptionListItemSchema -): UpdateExceptionListItemSchema | ExceptionListItemSchema => - flow( - removeCreatedAtCreatedByFromCommentsOnUpdate, - removeIdFromExceptionItemsEntries - )(exceptionItem); - -export const transformNewItemOutput = ( - exceptionItem: CreateExceptionListItemSchema -): CreateExceptionListItemSchema => flow(removeIdFromExceptionItemsEntries)(exceptionItem); - -/** - * Transforms the output of rules to compensate for technical debt or UI concerns such as - * ReactJS preferences for having ids within arrays if the data is not modeled that way. - * - * If you add a new transform of the input called "myNewTransform" do it - * in the form of: - * flow(addIdToExceptionItemEntries, myNewTransform)(exceptionItem) - * - * @param exceptionItem The exceptionItem to transform the output of - * @returns The exceptionItem transformed from the output - */ -export const transformInput = (exceptionItem: ExceptionListItemSchema): ExceptionListItemSchema => - flow(addIdToExceptionItemEntries)(exceptionItem); - -/** - * This adds an id to the incoming exception item entries as ReactJS prefers to have - * an id added to them for use as a stable id. Later if we decide to change the data - * model to have id's within the array then this code should be removed. If not, then - * this code should stay as an adapter for ReactJS. - * - * This does break the type system slightly as we are lying a bit to the type system as we return - * the same exceptionItem as we have previously but are augmenting the arrays with an id which TypeScript - * doesn't mind us doing here. However, downstream you will notice that you have an id when the type - * does not indicate it. In that case use (ExceptionItem & { id: string }) temporarily if you're using the id. If you're not, - * you can ignore the id and just use the normal TypeScript with ReactJS. - * - * @param exceptionItem The exceptionItem to add an id to the threat matches. - * @returns exceptionItem The exceptionItem but with id added to the exception item entries - */ -export const addIdToExceptionItemEntries = ( - exceptionItem: ExceptionListItemSchema -): ExceptionListItemSchema => { - const entries = exceptionItem.entries.map((entry) => { - if (entry.type === 'nested') { - return addIdToItem({ - ...entry, - entries: entry.entries.map((nestedEntry) => addIdToItem(nestedEntry)), - }); - } else { - return addIdToItem(entry); - } - }); - return { ...exceptionItem, entries }; -}; - -/** - * This removes an id from the exceptionItem entries as ReactJS prefers to have - * an id added to them for use as a stable id. Later if we decide to change the data - * model to have id's within the array then this code should be removed. If not, then - * this code should stay as an adapter for ReactJS. - * - * @param exceptionItem The exceptionItem to remove an id from the entries. - * @returns exceptionItem The exceptionItem but with id removed from the entries - */ -export const removeIdFromExceptionItemsEntries = ( - exceptionItem: T -): T => { - const { entries } = exceptionItem; - const entriesNoId = entries.map((entry) => { - if (entry.type === 'nested') { - return removeIdFromItem({ - ...entry, - entries: entry.entries.map((nestedEntry) => removeIdFromItem(nestedEntry)), - }); - } else { - return removeIdFromItem(entry); - } - }); - return { ...exceptionItem, entries: entriesNoId }; -}; - -/** - * This removes createdAt, createdBy from the exceptionItem if a comment was added to - * the Exception item, and return the comment message with id to prevent creating the commet - * twice - * @param exceptionItem The exceptionItem to remove createdAt, createdBy from the comments array. - * @returns exceptionItem The exceptionItem with comments do not have createdAt, createdBy. - */ -export const removeCreatedAtCreatedByFromCommentsOnUpdate = ( - exceptionItem: UpdateExceptionListItemSchema | ExceptionListItemSchema -) => { - const { comments } = exceptionItem; - if (!comments || !comments.length) return exceptionItem; - - const entriesNoCreatedAtAndBy = comments.map(({ comment, id }) => ({ - comment, - id, - })); - return { ...exceptionItem, comments: entriesNoCreatedAtAndBy }; -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts deleted file mode 100644 index 4ce917f5ad95b..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts +++ /dev/null @@ -1,317 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useMemo } from 'react'; -import type { - CreateExceptionListItemSchema, - ExceptionListItemSchema, - ExceptionListSchema, - UpdateExceptionListItemSchema, - ApiCallFindListsItemsMemoProps, - ApiCallMemoProps, - ApiListExportProps, - ApiCallGetExceptionFilterFromIdsMemoProps, - ApiCallGetExceptionFilterFromExceptionsMemoProps, - ApiListDuplicateProps, -} from '@kbn/securitysolution-io-ts-list-types'; -import * as Api from '@kbn/securitysolution-list-api'; -import { getIdsAndNamespaces } from '@kbn/securitysolution-list-utils'; -import type { HttpStart } from '@kbn/core-http-browser'; - -import { transformInput, transformNewItemOutput, transformOutput } from '../transforms'; - -export interface ExceptionsApi { - addExceptionListItem: (arg: { - listItem: CreateExceptionListItemSchema; - }) => Promise; - updateExceptionListItem: (arg: { - listItem: UpdateExceptionListItemSchema; - }) => Promise; - deleteExceptionItem: (arg: ApiCallMemoProps) => Promise; - deleteExceptionList: (arg: ApiCallMemoProps) => Promise; - duplicateExceptionList: (arg: ApiListDuplicateProps) => Promise; - getExceptionItem: ( - arg: ApiCallMemoProps & { onSuccess: (arg: ExceptionListItemSchema) => void } - ) => Promise; - getExceptionList: ( - arg: ApiCallMemoProps & { onSuccess: (arg: ExceptionListSchema) => void } - ) => Promise; - getExceptionListsItems: (arg: ApiCallFindListsItemsMemoProps) => Promise; - getExceptionFilterFromIds: (arg: ApiCallGetExceptionFilterFromIdsMemoProps) => Promise; - getExceptionFilterFromExceptions: ( - arg: ApiCallGetExceptionFilterFromExceptionsMemoProps - ) => Promise; - exportExceptionList: (arg: ApiListExportProps) => Promise; -} - -export const useApi = (http: HttpStart): ExceptionsApi => { - return useMemo( - (): ExceptionsApi => ({ - async addExceptionListItem({ - listItem, - }: { - listItem: CreateExceptionListItemSchema; - }): Promise { - const abortCtrl = new AbortController(); - const sanitizedItem: CreateExceptionListItemSchema = transformNewItemOutput(listItem); - - return Api.addExceptionListItem({ - http, - listItem: sanitizedItem, - signal: abortCtrl.signal, - }); - }, - async deleteExceptionItem({ - id, - namespaceType, - onSuccess, - onError, - }: ApiCallMemoProps): Promise { - const abortCtrl = new AbortController(); - - try { - await Api.deleteExceptionListItemById({ - http, - id, - namespaceType, - signal: abortCtrl.signal, - }); - onSuccess(); - } catch (error) { - onError(error); - } - }, - async deleteExceptionList({ - id, - namespaceType, - onSuccess, - onError, - }: ApiCallMemoProps): Promise { - const abortCtrl = new AbortController(); - - try { - await Api.deleteExceptionListById({ - http, - id, - namespaceType, - signal: abortCtrl.signal, - }); - onSuccess(); - } catch (error) { - onError(error); - } - }, - async duplicateExceptionList({ - includeExpiredExceptions, - listId, - namespaceType, - onError, - onSuccess, - }: ApiListDuplicateProps): Promise { - const abortCtrl = new AbortController(); - - try { - const newList = await Api.duplicateExceptionList({ - http, - includeExpiredExceptions, - listId, - namespaceType, - signal: abortCtrl.signal, - }); - onSuccess(newList); - } catch (error) { - onError(error); - } - }, - async exportExceptionList({ - id, - includeExpiredExceptions, - listId, - namespaceType, - onError, - onSuccess, - }: ApiListExportProps): Promise { - const abortCtrl = new AbortController(); - - try { - const blob = await Api.exportExceptionList({ - http, - id, - includeExpiredExceptions, - listId, - namespaceType, - signal: abortCtrl.signal, - }); - onSuccess(blob); - } catch (error) { - onError(error); - } - }, - async getExceptionItem({ - id, - namespaceType, - onSuccess, - onError, - }: ApiCallMemoProps & { onSuccess: (arg: ExceptionListItemSchema) => void }): Promise { - const abortCtrl = new AbortController(); - - try { - const item = transformInput( - await Api.fetchExceptionListItemById({ - http, - id, - namespaceType, - signal: abortCtrl.signal, - }) - ); - onSuccess(item); - } catch (error) { - onError(error); - } - }, - async getExceptionList({ - id, - namespaceType, - onSuccess, - onError, - }: ApiCallMemoProps & { onSuccess: (arg: ExceptionListSchema) => void }): Promise { - const abortCtrl = new AbortController(); - - try { - const list = await Api.fetchExceptionListById({ - http, - id, - namespaceType, - signal: abortCtrl.signal, - }); - onSuccess(list); - } catch (error) { - onError(error); - } - }, - async getExceptionListsItems({ - lists, - filter, - pagination, - showDetectionsListsOnly, - showEndpointListsOnly, - onSuccess, - onError, - }: ApiCallFindListsItemsMemoProps): Promise { - const abortCtrl = new AbortController(); - const { ids, namespaces } = getIdsAndNamespaces({ - lists, - showDetection: showDetectionsListsOnly, - showEndpoint: showEndpointListsOnly, - }); - - try { - if (ids.length > 0 && namespaces.length > 0) { - const { - data, - page, - per_page: perPage, - total, - } = await Api.fetchExceptionListsItemsByListIds({ - filter, - http, - listIds: ids, - namespaceTypes: namespaces, - pagination, - signal: abortCtrl.signal, - }); - onSuccess({ - // This data transform is UI specific and useful for UI concerns - // to compensate for the differences and preferences of how ReactJS might prefer - // data vs. how we want to model data. View `transformInput` for more details - exceptions: data.map((item) => transformInput(item)), - pagination: { - page, - perPage, - total, - }, - }); - } else { - onSuccess({ - exceptions: [], - pagination: { - page: 0, - perPage: pagination.perPage != null ? pagination.perPage : 0, - total: 0, - }, - }); - } - } catch (error) { - onError(error); - } - }, - async getExceptionFilterFromIds({ - exceptionListIds, - chunkSize, - alias, - excludeExceptions, - onSuccess, - onError, - }: ApiCallGetExceptionFilterFromIdsMemoProps): Promise { - const abortCtrl = new AbortController(); - try { - const { filter } = await Api.getExceptionFilterFromExceptionListIds({ - http, - exceptionListIds, - signal: abortCtrl.signal, - chunkSize, - alias, - excludeExceptions, - }); - onSuccess(filter); - } catch (error) { - onError(error); - } - }, - async getExceptionFilterFromExceptions({ - exceptions, - chunkSize, - alias, - excludeExceptions, - onSuccess, - onError, - }: ApiCallGetExceptionFilterFromExceptionsMemoProps): Promise { - const abortCtrl = new AbortController(); - try { - const { filter } = await Api.getExceptionFilterFromExceptions({ - http, - exceptions, - signal: abortCtrl.signal, - chunkSize, - alias, - excludeExceptions, - }); - onSuccess(filter); - } catch (error) { - onError(error); - } - }, - async updateExceptionListItem({ - listItem, - }: { - listItem: UpdateExceptionListItemSchema; - }): Promise { - const abortCtrl = new AbortController(); - const sanitizedItem: UpdateExceptionListItemSchema = transformOutput(listItem); - - return Api.updateExceptionListItem({ - http, - listItem: sanitizedItem, - signal: abortCtrl.signal, - }); - }, - }), - [http] - ); -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_create_list_index/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_create_list_index/index.ts deleted file mode 100644 index 06b87f510796c..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_create_list_index/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useMutation, useQueryClient } from '@tanstack/react-query'; - -import { createListIndex, ApiParams } from '@kbn/securitysolution-list-api'; -import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -import { READ_INDEX_QUERY_KEY } from '../constants'; - -const createListIndexWithOptionalSignal = withOptionalSignal(createListIndex); - -export const useCreateListIndex = ({ - http, - onError, -}: { - http: ApiParams['http']; - onError?: (err: unknown) => void; -}) => { - const queryClient = useQueryClient(); - - const { mutate, isLoading, error } = useMutation( - () => createListIndexWithOptionalSignal({ http }), - { - onSuccess: () => { - queryClient.invalidateQueries(READ_INDEX_QUERY_KEY); - }, - onError, - } - ); - - return { - start: mutate, - loading: isLoading, - error, - }; -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_create_list_item/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_create_list_item/index.ts deleted file mode 100644 index 98939d93185d6..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_create_list_item/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { UseMutationOptions } from '@tanstack/react-query'; -import type { ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import type { IHttpFetchError } from '@kbn/core-http-browser'; -import { useMutation } from '@tanstack/react-query'; -import { createListItem } from '@kbn/securitysolution-list-api'; -import type { CreateListItemParams } from '@kbn/securitysolution-list-api'; -import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -import { useInvalidateListItemQuery } from '../use_find_list_items'; - -const createListItemWithOptionalSignal = withOptionalSignal(createListItem); - -export const CREATE_LIST_ITEM_MUTATION_KEY = ['POST', 'LIST_ITEM_CREATE']; -type CreateListMutationParams = Omit; - -export const useCreateListItemMutation = ( - options?: UseMutationOptions, CreateListMutationParams> -) => { - const invalidateListItemQuery = useInvalidateListItemQuery(); - return useMutation, CreateListMutationParams>( - ({ listId, value, http }) => - createListItemWithOptionalSignal({ listId, value, http, refresh: 'wait_for' }), - { - ...options, - mutationKey: CREATE_LIST_ITEM_MUTATION_KEY, - onSettled: (...args) => { - invalidateListItemQuery(); - if (options?.onSettled) { - options.onSettled(...args); - } - }, - } - ); -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.test.ts b/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.test.ts deleted file mode 100644 index ca94eda81f950..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { renderHook, act } from '@testing-library/react'; - -import { UseCursorProps, useCursor } from '.'; - -describe('useCursor', () => { - it('returns undefined cursor if no values have been set', () => { - const { result } = renderHook((props: UseCursorProps) => useCursor(props), { - initialProps: { pageIndex: 0, pageSize: 0 }, - }); - - expect(result.current[0]).toBeUndefined(); - }); - - it('retrieves a cursor for the next page of a given page size', () => { - const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { - initialProps: { pageIndex: 0, pageSize: 0 }, - }); - rerender({ pageIndex: 1, pageSize: 1 }); - act(() => { - result.current[1]('new_cursor'); - }); - - expect(result.current[0]).toBeUndefined(); - - rerender({ pageIndex: 2, pageSize: 1 }); - expect(result.current[0]).toEqual('new_cursor'); - }); - - it('returns undefined cursor for an unknown search', () => { - const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { - initialProps: { pageIndex: 0, pageSize: 0 }, - }); - act(() => { - result.current[1]('new_cursor'); - }); - - rerender({ pageIndex: 1, pageSize: 2 }); - expect(result.current[0]).toBeUndefined(); - }); - - it('remembers cursor through rerenders', () => { - const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { - initialProps: { pageIndex: 0, pageSize: 0 }, - }); - - rerender({ pageIndex: 1, pageSize: 1 }); - act(() => { - result.current[1]('new_cursor'); - }); - - rerender({ pageIndex: 2, pageSize: 1 }); - expect(result.current[0]).toEqual('new_cursor'); - - rerender({ pageIndex: 0, pageSize: 0 }); - expect(result.current[0]).toBeUndefined(); - - rerender({ pageIndex: 2, pageSize: 1 }); - expect(result.current[0]).toEqual('new_cursor'); - }); - - it('remembers multiple cursors', () => { - const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { - initialProps: { pageIndex: 0, pageSize: 0 }, - }); - - rerender({ pageIndex: 1, pageSize: 1 }); - act(() => { - result.current[1]('new_cursor'); - }); - rerender({ pageIndex: 2, pageSize: 2 }); - act(() => { - result.current[1]('another_cursor'); - }); - - rerender({ pageIndex: 2, pageSize: 1 }); - expect(result.current[0]).toEqual('new_cursor'); - - rerender({ pageIndex: 3, pageSize: 2 }); - expect(result.current[0]).toEqual('another_cursor'); - }); - - it('returns the "nearest" cursor for the given page size', () => { - const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { - initialProps: { pageIndex: 0, pageSize: 0 }, - }); - - rerender({ pageIndex: 1, pageSize: 2 }); - act(() => { - result.current[1]('cursor1'); - }); - rerender({ pageIndex: 2, pageSize: 2 }); - act(() => { - result.current[1]('cursor2'); - }); - rerender({ pageIndex: 3, pageSize: 2 }); - act(() => { - result.current[1]('cursor3'); - }); - - rerender({ pageIndex: 2, pageSize: 2 }); - expect(result.current[0]).toEqual('cursor1'); - - rerender({ pageIndex: 3, pageSize: 2 }); - expect(result.current[0]).toEqual('cursor2'); - - rerender({ pageIndex: 4, pageSize: 2 }); - expect(result.current[0]).toEqual('cursor3'); - - rerender({ pageIndex: 6, pageSize: 2 }); - expect(result.current[0]).toEqual('cursor3'); - }); -}); diff --git a/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.ts deleted file mode 100644 index b8e8df0438828..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useCallback, useState } from 'react'; - -export interface UseCursorProps { - pageIndex: number; - pageSize: number; -} -type Cursor = string | undefined; -type SetCursor = (cursor: Cursor) => void; -type UseCursor = (props: UseCursorProps) => [Cursor, SetCursor]; - -const hash = (props: UseCursorProps): string => JSON.stringify(props); - -export const useCursor: UseCursor = ({ pageIndex, pageSize }) => { - const [cache, setCache] = useState>({}); - - const setCursor = useCallback( - (cursor) => { - setCache({ - ...cache, - [hash({ pageIndex: pageIndex + 1, pageSize })]: cursor, - }); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [pageIndex, pageSize] - ); - - let cursor: Cursor; - for (let i = pageIndex; i >= 0; i--) { - const currentProps = { pageIndex: i, pageSize }; - cursor = cache[hash(currentProps)]; - if (cursor) { - break; - } - } - - return [cursor, setCursor]; -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_delete_list/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_delete_list/index.ts deleted file mode 100644 index fe88e19f84892..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_delete_list/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { deleteList } from '@kbn/securitysolution-list-api'; -import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -const deleteListWithOptionalSignal = withOptionalSignal(deleteList); - -export const useDeleteList = () => useAsync(deleteListWithOptionalSignal); diff --git a/packages/kbn-securitysolution-list-hooks/src/use_delete_list_item/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_delete_list_item/index.ts deleted file mode 100644 index 63107edda73a9..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_delete_list_item/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { UseMutationOptions } from '@tanstack/react-query'; -import type { ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { useMutation } from '@tanstack/react-query'; -import { deleteListItem } from '@kbn/securitysolution-list-api'; -import type { IHttpFetchError } from '@kbn/core-http-browser'; -import type { DeleteListItemParams } from '@kbn/securitysolution-list-api'; -import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; -import { useInvalidateListItemQuery } from '../use_find_list_items'; - -const deleteListItemWithOptionalSignal = withOptionalSignal(deleteListItem); - -export const DELETE_LIST_ITEM_MUTATION_KEY = ['POST', ' DELETE_LIST_ITEM_MUTATION']; -type DeleteListMutationParams = Omit; - -export const useDeleteListItemMutation = ( - options?: UseMutationOptions, DeleteListMutationParams> -) => { - const invalidateListItemQuery = useInvalidateListItemQuery(); - return useMutation, DeleteListMutationParams>( - ({ id, http }) => deleteListItemWithOptionalSignal({ id, http }), - { - ...options, - mutationKey: DELETE_LIST_ITEM_MUTATION_KEY, - onSettled: (...args) => { - invalidateListItemQuery(); - if (options?.onSettled) { - options.onSettled(...args); - } - }, - } - ); -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts deleted file mode 100644 index 2907de45eba40..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import type { - ExceptionListSchema, - UseExceptionListsProps, - Pagination, - Sort, -} from '@kbn/securitysolution-io-ts-list-types'; -import { fetchExceptionLists } from '@kbn/securitysolution-list-api'; - -import { getFilters } from '@kbn/securitysolution-list-utils'; - -export type Func = () => void; -export type ReturnExceptionLists = [ - loading: boolean, - exceptionLists: ExceptionListSchema[], - pagination: Pagination, - setPagination: React.Dispatch>, - fetchLists: Func | null, - sort: Sort, - setSort: React.Dispatch> -]; - -const DEFAULT_PAGINATION = { - page: 1, - perPage: 20, - total: 0, -}; - -const DEFAULT_SORT = { - field: 'created_at', - order: 'desc', -}; - -/** - * Hook for fetching ExceptionLists - * - * @param http Kibana http service - * @param errorMessage message shown to user if error occurs - * @param filterOptions filter by certain fields - * @param namespaceTypes spaces to be searched - * @param notifications kibana service for displaying toasters - * @param hideLists a list of listIds we don't want to query - * @param initialPagination - * - */ -export const useExceptionLists = ({ - errorMessage, - http, - initialPagination = DEFAULT_PAGINATION, - filterOptions = {}, - namespaceTypes, - notifications, - hideLists = [], - initialSort = DEFAULT_SORT, -}: UseExceptionListsProps): ReturnExceptionLists => { - const [exceptionLists, setExceptionLists] = useState([]); - const [pagination, setPagination] = useState(initialPagination); - const [sort, setSort] = useState(initialSort); - const [loading, setLoading] = useState(true); - const abortCtrlRef = useRef(); - - const namespaceTypesAsString = useMemo(() => namespaceTypes.join(','), [namespaceTypes]); - const filters = useMemo( - (): string => - getFilters({ - filters: filterOptions, - namespaceTypes, - hideLists, - }), - [namespaceTypes, filterOptions, hideLists] - ); - - const fetchData = useCallback(async (): Promise => { - try { - setLoading(true); - - abortCtrlRef.current = new AbortController(); - - const { - page, - per_page: perPage, - total, - data, - } = await fetchExceptionLists({ - filters, - http, - namespaceTypes: namespaceTypesAsString, - pagination: { - page: pagination.page, - perPage: pagination.perPage, - }, - sort, - signal: abortCtrlRef.current.signal, - }); - - setPagination({ - page, - perPage, - total, - }); - setExceptionLists(data); - setLoading(false); - } catch (error) { - if (error.name !== 'AbortError') { - notifications.toasts.addError(error, { - title: errorMessage, - }); - setExceptionLists([]); - setPagination(DEFAULT_PAGINATION); - setLoading(false); - } - } - }, [ - errorMessage, - filters, - http, - namespaceTypesAsString, - notifications.toasts, - pagination.page, - pagination.perPage, - sort, - ]); - - useEffect(() => { - fetchData(); - - return (): void => { - abortCtrlRef.current?.abort(); - }; - }, [fetchData]); - - return [loading, exceptionLists, pagination, setPagination, fetchData, sort, setSort]; -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_export_list/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_export_list/index.ts deleted file mode 100644 index 77a213cc47b9c..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_export_list/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { exportList } from '@kbn/securitysolution-list-api'; -import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -const exportListWithOptionalSignal = withOptionalSignal(exportList); - -export const useExportList = () => useAsync(exportListWithOptionalSignal); diff --git a/packages/kbn-securitysolution-list-hooks/src/use_find_list_items/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_find_list_items/index.ts deleted file mode 100644 index f385408d26fdd..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_find_list_items/index.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useCallback } from 'react'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { findListItems, ApiParams } from '@kbn/securitysolution-list-api'; -import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; -import { useCursor } from '../use_cursor'; - -const findListItemsWithOptionalSignal = withOptionalSignal(findListItems); - -const FIND_LIST_ITEMS_QUERY_KEY = 'FIND_LIST_ITEMS'; - -export const useInvalidateListItemQuery = () => { - const queryClient = useQueryClient(); - - return useCallback(() => { - queryClient.invalidateQueries([FIND_LIST_ITEMS_QUERY_KEY], { - refetchType: 'active', - }); - }, [queryClient]); -}; - -export const useFindListItems = ({ - pageIndex, - pageSize, - sortField, - sortOrder, - listId, - filter, - http, -}: { - pageIndex: number; - pageSize: number; - sortField: string; - sortOrder: 'asc' | 'desc'; - listId: string; - filter: string; - http: ApiParams['http']; -}) => { - const [cursor, setCursor] = useCursor({ pageIndex, pageSize }); - return useQuery( - [FIND_LIST_ITEMS_QUERY_KEY, pageIndex, pageSize, sortField, sortOrder, listId, filter], - async ({ signal }) => { - const response = await findListItemsWithOptionalSignal({ - http, - signal, - pageIndex, - pageSize, - sortField, - sortOrder, - listId, - cursor, - filter, - }); - return response; - }, - { - keepPreviousData: true, - refetchOnWindowFocus: false, - retry: false, - onSuccess: (data) => { - if (data?.cursor) { - setCursor(data?.cursor); - } - }, - } - ); -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.test.ts b/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.test.ts deleted file mode 100644 index fcce54ac3be32..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { waitFor, renderHook, act } from '@testing-library/react'; - -import { useFindLists } from '.'; -import { httpServiceMock } from '@kbn/core-http-browser-mocks'; -import * as Api from '@kbn/securitysolution-list-api'; - -import { getFoundListSchemaMock } from '../mocks/response/found_list_schema.mock'; - -jest.mock('@kbn/securitysolution-list-api'); - -describe('useFindLists', () => { - let httpMock: ReturnType; - - beforeEach(() => { - httpMock = httpServiceMock.createStartContract(); - (Api.findLists as jest.Mock).mockResolvedValue(getFoundListSchemaMock()); - }); - - it('invokes Api.findLists', async () => { - const { result } = renderHook(() => useFindLists()); - act(() => { - result.current.start({ http: httpMock, pageIndex: 1, pageSize: 10 }); - }); - await waitFor(() => - expect(Api.findLists).toHaveBeenCalledWith( - expect.objectContaining({ http: httpMock, pageIndex: 1, pageSize: 10 }) - ) - ); - }); -}); diff --git a/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.ts deleted file mode 100644 index a33e3ba9f8607..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { findLists } from '@kbn/securitysolution-list-api'; -import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -const findListsWithOptionalSignal = withOptionalSignal(findLists); - -export const useFindLists = () => useAsync(findListsWithOptionalSignal); diff --git a/packages/kbn-securitysolution-list-hooks/src/use_find_lists_by_size/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_find_lists_by_size/index.ts deleted file mode 100644 index 25027ee3901d2..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_find_lists_by_size/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { findListsBySize } from '@kbn/securitysolution-list-api'; -import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -const findListsBySizeWithOptionalSignal = withOptionalSignal(findListsBySize); - -export const useFindListsBySize = () => useAsync(findListsBySizeWithOptionalSignal); diff --git a/packages/kbn-securitysolution-list-hooks/src/use_get_list_by_id/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_get_list_by_id/index.ts deleted file mode 100644 index 030fbcfae829f..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_get_list_by_id/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useQuery } from '@tanstack/react-query'; -import { getListById, ApiParams } from '@kbn/securitysolution-list-api'; -import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -const getListByIdWithOptionalSignal = withOptionalSignal(getListById); - -const GET_LIST_BY_ID_QUERY_KEY = 'GET_LIST_BY_ID'; -export const useGetListById = ({ http, id }: { http: ApiParams['http']; id: string }) => { - return useQuery( - [GET_LIST_BY_ID_QUERY_KEY, id], - async ({ signal }) => { - const respone = await getListByIdWithOptionalSignal({ http, signal, id }); - return respone; - }, - { - refetchOnWindowFocus: false, - } - ); -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_import_list/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_import_list/index.ts deleted file mode 100644 index 1bbccd1448017..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_import_list/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { importList } from '@kbn/securitysolution-list-api'; -import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -const importListWithOptionalSignal = withOptionalSignal(importList); - -export const useImportList = () => useAsync(importListWithOptionalSignal); diff --git a/packages/kbn-securitysolution-list-hooks/src/use_patch_list_item/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_patch_list_item/index.ts deleted file mode 100644 index cdae3015cff81..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_patch_list_item/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { UseMutationOptions } from '@tanstack/react-query'; -import type { ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { useMutation } from '@tanstack/react-query'; -import type { PatchListItemParams } from '@kbn/securitysolution-list-api'; -import { patchListItem } from '@kbn/securitysolution-list-api'; -import type { IHttpFetchError } from '@kbn/core-http-browser'; -import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; -import { useInvalidateListItemQuery } from '../use_find_list_items'; - -const patchListItemWithOptionalSignal = withOptionalSignal(patchListItem); - -export const PATCH_LIST_ITEM_MUTATION_KEY = ['PATCH', 'LIST_ITEM_MUTATION']; -type PatchListMutationParams = Omit; - -export const usePatchListItemMutation = ( - options?: UseMutationOptions, PatchListMutationParams> -) => { - const invalidateListItemQuery = useInvalidateListItemQuery(); - return useMutation, PatchListMutationParams>( - ({ id, value, _version, http }: PatchListMutationParams) => - patchListItemWithOptionalSignal({ id, value, http, refresh: 'true', _version }), - { - ...options, - mutationKey: PATCH_LIST_ITEM_MUTATION_KEY, - onSettled: (...args) => { - invalidateListItemQuery(); - if (options?.onSettled) { - options.onSettled(...args); - } - }, - } - ); -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_item/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_item/index.ts deleted file mode 100644 index 79f8748345fdf..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_item/index.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { Dispatch, useEffect, useRef, useState } from 'react'; -import type { - CreateExceptionListItemSchema, - PersistHookProps, - UpdateExceptionListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { addExceptionListItem, updateExceptionListItem } from '@kbn/securitysolution-list-api'; - -import { transformNewItemOutput, transformOutput } from '../transforms'; - -interface PersistReturnExceptionItem { - isLoading: boolean; - isSaved: boolean; -} - -export type ReturnPersistExceptionItem = [ - PersistReturnExceptionItem, - Dispatch -]; - -// TODO: Add this to @kbn/securitysolution-list-hooks - -/** - * Hook for creating or updating ExceptionListItem - * - * @param http Kibana http service - * @param onError error callback - * - */ -export const usePersistExceptionItem = ({ - http, - onError, -}: PersistHookProps): ReturnPersistExceptionItem => { - const [exceptionListItem, setExceptionItem] = useState< - CreateExceptionListItemSchema | UpdateExceptionListItemSchema | null - >(null); - const [isSaved, setIsSaved] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const isUpdateExceptionItem = (item: unknown): item is UpdateExceptionListItemSchema => - Boolean(item && (item as UpdateExceptionListItemSchema).id != null); - const isSubscribed = useRef(false); - - useEffect(() => { - let abortCtrl: AbortController | null = null; - isSubscribed.current = true; - setIsSaved(false); - - const saveExceptionItem = async (): Promise => { - if (exceptionListItem === null) { - return; - } - - try { - abortCtrl = new AbortController(); - setIsLoading(true); - - if (isUpdateExceptionItem(exceptionListItem)) { - // Please see `x-pack/plugins/lists/public/exceptions/transforms.ts` doc notes - // for context around the temporary `id` - const transformedList = transformOutput(exceptionListItem); - - await updateExceptionListItem({ - http, - listItem: transformedList, - signal: abortCtrl.signal, - }); - } else { - // Please see `x-pack/plugins/lists/public/exceptions/transforms.ts` doc notes - // for context around the temporary `id` - const transformedList = transformNewItemOutput(exceptionListItem); - - await addExceptionListItem({ - http, - listItem: transformedList, - signal: abortCtrl.signal, - }); - } - - if (isSubscribed.current) { - setIsSaved(true); - } - } catch (error) { - if (isSubscribed.current) { - onError(error); - } - } finally { - if (isSubscribed.current) { - setIsLoading(false); - } - } - }; - - saveExceptionItem(); - - return (): void => { - isSubscribed.current = false; - abortCtrl?.abort(); - }; - }, [http, exceptionListItem, onError]); - - return [{ isLoading, isSaved }, setExceptionItem]; -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_list/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_list/index.ts deleted file mode 100644 index 8648516d008cc..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_list/index.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { Dispatch, useEffect, useState } from 'react'; -import type { - AddExceptionList, - PersistHookProps, - UpdateExceptionListSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { addExceptionList, updateExceptionList } from '@kbn/securitysolution-list-api'; - -interface PersistReturnExceptionList { - isLoading: boolean; - isSaved: boolean; -} - -export type ReturnPersistExceptionList = [ - PersistReturnExceptionList, - Dispatch -]; - -/** - * Hook for creating or updating ExceptionList - * - * @param http Kibana http service - * @param onError error callback - * - */ -export const usePersistExceptionList = ({ - http, - onError, -}: PersistHookProps): ReturnPersistExceptionList => { - const [exceptionList, setExceptionList] = useState(null); - const [isSaved, setIsSaved] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const isUpdateExceptionList = (item: unknown): item is UpdateExceptionListSchema => - Boolean(item && (item as UpdateExceptionListSchema).id != null); - - useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); - setIsSaved(false); - - const saveExceptionList = async (): Promise => { - if (exceptionList != null) { - try { - setIsLoading(true); - if (isUpdateExceptionList(exceptionList)) { - await updateExceptionList({ http, list: exceptionList, signal: abortCtrl.signal }); - } else { - await addExceptionList({ http, list: exceptionList, signal: abortCtrl.signal }); - } - if (isSubscribed) { - setIsSaved(true); - } - } catch (error) { - if (isSubscribed) { - onError(error); - } - } - if (isSubscribed) { - setIsLoading(false); - } - } - }; - - saveExceptionList(); - return (): void => { - isSubscribed = false; - abortCtrl.abort(); - }; - }, [http, exceptionList, onError]); - - return [{ isLoading, isSaved }, setExceptionList]; -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_read_list_index/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_read_list_index/index.ts deleted file mode 100644 index 4853f0a7480a8..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_read_list_index/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { useQuery } from '@tanstack/react-query'; - -import { readListIndex, ApiParams } from '@kbn/securitysolution-list-api'; -import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -import { READ_INDEX_QUERY_KEY } from '../constants'; - -const readListIndexWithOptionalSignal = withOptionalSignal(readListIndex); - -export const useReadListIndex = ({ - http, - isEnabled, - onError, -}: { - isEnabled: boolean; - http: ApiParams['http']; - onError?: (err: unknown) => void; -}) => { - const query = useQuery( - READ_INDEX_QUERY_KEY, - async ({ signal }) => { - if (!isEnabled) { - return null; - } - - return readListIndexWithOptionalSignal({ http, signal }); - }, - { - onError, - retry: false, - refetchOnWindowFocus: false, - enabled: isEnabled, - staleTime: Infinity, - } - ); - - return { - result: query.data, - loading: query.isFetching, - error: query.error, - }; -}; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_read_list_privileges/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_read_list_privileges/index.ts deleted file mode 100644 index 42a055c168085..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/use_read_list_privileges/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { readListPrivileges } from '@kbn/securitysolution-list-api'; -import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; - -const readListPrivilegesWithOptionalSignal = withOptionalSignal(readListPrivileges); - -export const useReadListPrivileges = () => useAsync(readListPrivilegesWithOptionalSignal); diff --git a/packages/kbn-securitysolution-list-hooks/tsconfig.json b/packages/kbn-securitysolution-list-hooks/tsconfig.json deleted file mode 100644 index 53e105e609750..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts", - ], - "kbn_references": [ - "@kbn/securitysolution-hook-utils", - "@kbn/securitysolution-io-ts-list-types", - "@kbn/securitysolution-list-api", - "@kbn/securitysolution-list-utils", - "@kbn/securitysolution-utils", - "@kbn/core-http-browser-mocks", - "@kbn/core-http-browser", - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-list-utils/index.ts b/packages/kbn-securitysolution-list-utils/index.ts deleted file mode 100644 index c5999a044a188..0000000000000 --- a/packages/kbn-securitysolution-list-utils/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './src/autocomplete_operators'; -export * from './src/get_exception_list_type'; -export * from './src/get_filters'; -export * from './src/get_general_filters'; -export * from './src/get_ids_and_namespaces'; -export * from './src/get_saved_object_type'; -export * from './src/get_saved_object_types'; -export * from './src/has_large_value_list'; -export * from './src/helpers'; -export * from './src/types'; diff --git a/packages/kbn-securitysolution-list-utils/jest.config.js b/packages/kbn-securitysolution-list-utils/jest.config.js deleted file mode 100644 index b24a4fa543f78..0000000000000 --- a/packages/kbn-securitysolution-list-utils/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-list-utils'], -}; diff --git a/packages/kbn-securitysolution-list-utils/package.json b/packages/kbn-securitysolution-list-utils/package.json deleted file mode 100644 index e9ace6e302344..0000000000000 --- a/packages/kbn-securitysolution-list-utils/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@kbn/securitysolution-list-utils", - "version": "1.0.0", - "description": "security solution list utilities", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true, - "sideEffects": false -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts b/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts deleted file mode 100644 index b4b1eec6be342..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { i18n } from '@kbn/i18n'; -import { - ListOperatorEnum as OperatorEnum, - ListOperatorTypeEnum as OperatorTypeEnum, -} from '@kbn/securitysolution-io-ts-list-types'; -import { OperatorOption } from '../types'; - -export const isOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.isOperatorLabel', { - defaultMessage: 'is', - }), - operator: OperatorEnum.INCLUDED, - type: OperatorTypeEnum.MATCH, - value: 'is', -}; - -export const isNotOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.isNotOperatorLabel', { - defaultMessage: 'is not', - }), - operator: OperatorEnum.EXCLUDED, - type: OperatorTypeEnum.MATCH, - value: 'is_not', -}; - -export const isOneOfOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.isOneOfOperatorLabel', { - defaultMessage: 'is one of', - }), - operator: OperatorEnum.INCLUDED, - type: OperatorTypeEnum.MATCH_ANY, - value: 'is_one_of', -}; - -export const isNotOneOfOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.isNotOneOfOperatorLabel', { - defaultMessage: 'is not one of', - }), - operator: OperatorEnum.EXCLUDED, - type: OperatorTypeEnum.MATCH_ANY, - value: 'is_not_one_of', -}; - -export const existsOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.existsOperatorLabel', { - defaultMessage: 'exists', - }), - operator: OperatorEnum.INCLUDED, - type: OperatorTypeEnum.EXISTS, - value: 'exists', -}; - -export const doesNotExistOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.doesNotExistOperatorLabel', { - defaultMessage: 'does not exist', - }), - operator: OperatorEnum.EXCLUDED, - type: OperatorTypeEnum.EXISTS, - value: 'does_not_exist', -}; - -export const isInListOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.isInListOperatorLabel', { - defaultMessage: 'is in list', - }), - operator: OperatorEnum.INCLUDED, - type: OperatorTypeEnum.LIST, - value: 'is_in_list', -}; - -export const isNotInListOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.isNotInListOperatorLabel', { - defaultMessage: 'is not in list', - }), - operator: OperatorEnum.EXCLUDED, - type: OperatorTypeEnum.LIST, - value: 'is_not_in_list', -}; - -export const matchesOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.matchesOperatorLabel', { - defaultMessage: 'matches', - }), - operator: OperatorEnum.INCLUDED, - type: OperatorTypeEnum.WILDCARD, - value: 'matches', -}; - -export const doesNotMatchOperator: OperatorOption = { - message: i18n.translate('lists.exceptions.doesNotMatchOperatorLabel', { - defaultMessage: 'does not match', - }), - operator: OperatorEnum.EXCLUDED, - type: OperatorTypeEnum.WILDCARD, - value: 'does_not_match', -}; - -export const EVENT_FILTERS_OPERATORS: OperatorOption[] = [ - isOperator, - isNotOperator, - isOneOfOperator, - isNotOneOfOperator, - matchesOperator, - doesNotMatchOperator, -]; - -/* - * !IMPORTANT! - Please only add to this list if it is an operator - * supported by the detection engine. - */ -export const DETECTION_ENGINE_EXCEPTION_OPERATORS: OperatorOption[] = [ - isOperator, - isNotOperator, - isOneOfOperator, - isNotOneOfOperator, - existsOperator, - doesNotExistOperator, - isInListOperator, - isNotInListOperator, - matchesOperator, - doesNotMatchOperator, -]; - -export const ALL_OPERATORS: OperatorOption[] = [ - isOperator, - isNotOperator, - isOneOfOperator, - isNotOneOfOperator, - existsOperator, - doesNotExistOperator, - isInListOperator, - isNotInListOperator, - matchesOperator, - doesNotMatchOperator, -]; - -export const EXCEPTION_OPERATORS_SANS_LISTS: OperatorOption[] = [ - isOperator, - isNotOperator, - isOneOfOperator, - isNotOneOfOperator, - existsOperator, - doesNotExistOperator, - matchesOperator, - doesNotMatchOperator, -]; - -export const EXCEPTION_OPERATORS_ONLY_LISTS: OperatorOption[] = [ - isInListOperator, - isNotInListOperator, -]; diff --git a/packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts b/packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts deleted file mode 100644 index 568436c487dea..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; - -import { exceptionListAgnosticSavedObjectType } from '../types'; - -export const getExceptionListType = ({ - savedObjectType, -}: { - savedObjectType: string; -}): NamespaceType => { - if (savedObjectType === exceptionListAgnosticSavedObjectType) { - return 'agnostic'; - } else { - return 'single'; - } -}; diff --git a/packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts b/packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts deleted file mode 100644 index 76b9eeda44f86..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { getFilters } from '.'; - -describe('getFilters', () => { - describe('single', () => { - test('it properly formats when no filters and hide lists contains few list ids', () => { - const filter = getFilters({ - filters: {}, - namespaceTypes: ['single'], - hideLists: ['listId-1', 'listId-2', 'listId-3'], - }); - - expect(filter).toEqual( - '(not exception-list.attributes.list_id: listId-1*) AND (not exception-list.attributes.list_id: listId-2*) AND (not exception-list.attributes.list_id: listId-3*)' - ); - }); - test('it properly formats when no filters and hide lists contains one list id', () => { - const filter = getFilters({ - filters: {}, - namespaceTypes: ['single'], - hideLists: ['listId-1'], - }); - - expect(filter).toEqual('(not exception-list.attributes.list_id: listId-1*)'); - }); - test('it properly formats when no filters and no hide lists', () => { - const filter = getFilters({ - filters: {}, - namespaceTypes: ['single'], - hideLists: [], - }); - - expect(filter).toEqual(''); - }); - test('it properly formats when filters passed and hide lists contains few list ids', () => { - const filter = getFilters({ - filters: { created_by: 'moi', name: 'Sample' }, - namespaceTypes: ['single'], - hideLists: ['listId-1', 'listId-2', 'listId-3'], - }); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: listId-1*) AND (not exception-list.attributes.list_id: listId-2*) AND (not exception-list.attributes.list_id: listId-3*)' - ); - }); - test('it properly formats when filters passed and hide lists contains one list id', () => { - const filter = getFilters({ - filters: { created_by: 'moi', name: 'Sample' }, - namespaceTypes: ['single'], - hideLists: ['listId-1'], - }); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: listId-1*)' - ); - }); - test('it properly formats when filters passed and no hide lists', () => { - const filter = getFilters({ - filters: { created_by: 'moi', name: 'Sample' }, - namespaceTypes: ['single'], - hideLists: [], - }); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample)' - ); - }); - }); - - describe('agnostic', () => { - test('it properly formats when no filters and hide lists contains few list ids', () => { - const filter = getFilters({ - filters: {}, - namespaceTypes: ['agnostic'], - hideLists: ['listId-1', 'listId-2', 'listId-3'], - }); - - expect(filter).toEqual( - '(not exception-list-agnostic.attributes.list_id: listId-1*) AND (not exception-list-agnostic.attributes.list_id: listId-2*) AND (not exception-list-agnostic.attributes.list_id: listId-3*)' - ); - }); - test('it properly formats when no filters and hide lists contains one list id', () => { - const filter = getFilters({ - filters: {}, - namespaceTypes: ['agnostic'], - hideLists: ['listId-1'], - }); - - expect(filter).toEqual('(not exception-list-agnostic.attributes.list_id: listId-1*)'); - }); - test('it properly formats when no filters and no hide lists', () => { - const filter = getFilters({ - filters: {}, - namespaceTypes: ['agnostic'], - hideLists: [], - }); - - expect(filter).toEqual(''); - }); - test('it properly formats when filters passed and hide lists contains few list ids', () => { - const filter = getFilters({ - filters: { created_by: 'moi', name: 'Sample' }, - namespaceTypes: ['agnostic'], - hideLists: ['listId-1', 'listId-2', 'listId-3'], - }); - - expect(filter).toEqual( - '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list-agnostic.attributes.list_id: listId-1*) AND (not exception-list-agnostic.attributes.list_id: listId-2*) AND (not exception-list-agnostic.attributes.list_id: listId-3*)' - ); - }); - test('it properly formats when filters passed and hide lists contains one list id', () => { - const filter = getFilters({ - filters: { created_by: 'moi', name: 'Sample' }, - namespaceTypes: ['agnostic'], - hideLists: ['listId-1'], - }); - - expect(filter).toEqual( - '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list-agnostic.attributes.list_id: listId-1*)' - ); - }); - test('it properly formats when filters passed and no hide lists', () => { - const filter = getFilters({ - filters: { created_by: 'moi', name: 'Sample' }, - namespaceTypes: ['agnostic'], - hideLists: [], - }); - - expect(filter).toEqual( - '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample)' - ); - }); - }); - - describe('single, agnostic', () => { - test('it properly formats when no filters and hide lists contains few list ids', () => { - const filter = getFilters({ - filters: {}, - namespaceTypes: ['single', 'agnostic'], - hideLists: ['listId-1', 'listId-2', 'listId-3'], - }); - - expect(filter).toEqual( - '(not exception-list.attributes.list_id: listId-1* AND not exception-list-agnostic.attributes.list_id: listId-1*) AND (not exception-list.attributes.list_id: listId-2* AND not exception-list-agnostic.attributes.list_id: listId-2*) AND (not exception-list.attributes.list_id: listId-3* AND not exception-list-agnostic.attributes.list_id: listId-3*)' - ); - }); - test('it properly formats when no filters and hide lists contains one list id', () => { - const filter = getFilters({ - filters: {}, - namespaceTypes: ['single', 'agnostic'], - hideLists: ['listId-1'], - }); - - expect(filter).toEqual( - '(not exception-list.attributes.list_id: listId-1* AND not exception-list-agnostic.attributes.list_id: listId-1*)' - ); - }); - test('it properly formats when no filters and no hide lists', () => { - const filter = getFilters({ - filters: {}, - namespaceTypes: ['single', 'agnostic'], - hideLists: [], - }); - - expect(filter).toEqual(''); - }); - test('it properly formats when filters passed and hide lists contains few list ids', () => { - const filter = getFilters({ - filters: { created_by: 'moi', name: 'Sample' }, - namespaceTypes: ['single', 'agnostic'], - hideLists: ['listId-1', 'listId-2', 'listId-3'], - }); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: listId-1* AND not exception-list-agnostic.attributes.list_id: listId-1*) AND (not exception-list.attributes.list_id: listId-2* AND not exception-list-agnostic.attributes.list_id: listId-2*) AND (not exception-list.attributes.list_id: listId-3* AND not exception-list-agnostic.attributes.list_id: listId-3*)' - ); - }); - test('it properly formats when filters passed and hide lists contains one list id', () => { - const filter = getFilters({ - filters: { created_by: 'moi', name: 'Sample' }, - namespaceTypes: ['single', 'agnostic'], - hideLists: ['listId-1'], - }); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: listId-1* AND not exception-list-agnostic.attributes.list_id: listId-1*)' - ); - }); - test('it properly formats when filters passed and no hide lists', () => { - const filter = getFilters({ - filters: { created_by: 'moi', name: 'Sample' }, - namespaceTypes: ['single', 'agnostic'], - hideLists: [], - }); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample)' - ); - }); - }); -}); diff --git a/packages/kbn-securitysolution-list-utils/src/get_filters/index.ts b/packages/kbn-securitysolution-list-utils/src/get_filters/index.ts deleted file mode 100644 index 6ca3119855b34..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/get_filters/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ExceptionListFilter, NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; -import { getGeneralFilters } from '../get_general_filters'; -import { getSavedObjectTypes } from '../get_saved_object_types'; -export interface GetFiltersParams { - filters: ExceptionListFilter; - namespaceTypes: NamespaceType[]; - hideLists: readonly string[]; -} - -export const getFilters = ({ filters, namespaceTypes, hideLists }: GetFiltersParams): string => { - const namespaces = getSavedObjectTypes({ namespaceType: namespaceTypes }); - const generalFilters = getGeneralFilters(filters, namespaces); - const hideListsFilters = hideLists.map((listId) => { - const filtersByNamespace = namespaces.map((namespace) => { - return `not ${namespace}.attributes.list_id: ${listId}*`; - }); - return `(${filtersByNamespace.join(' AND ')})`; - }); - - return [generalFilters, ...hideListsFilters] - .filter((filter) => filter.trim() !== '') - .join(' AND '); -}; diff --git a/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts b/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts deleted file mode 100644 index b349c57ab3868..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import { getGeneralFilters } from '.'; - -describe('getGeneralFilters', () => { - test('it returns empty string if no filters', () => { - const filters = getGeneralFilters({}, ['exception-list']); - - expect(filters).toEqual(''); - }); - - test('it properly formats filters when one namespace type passed in', () => { - const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, ['exception-list']); - - expect(filters).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample)' - ); - }); - - test('it properly formats filters when two namespace types passed in', () => { - const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, [ - 'exception-list', - 'exception-list-agnostic', - ]); - - expect(filters).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample)' - ); - }); - - test('it properly formats filters when two types are passed in', () => { - const filters = getGeneralFilters( - { - created_by: 'moi', - name: 'Sample', - types: [ExceptionListTypeEnum.DETECTION, ExceptionListTypeEnum.RULE_DEFAULT], - }, - ['exception-list', 'exception-list-agnostic'] - ); - - expect(filters).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (exception-list.attributes.type:detection OR exception-list.attributes.type:rule_default OR exception-list-agnostic.attributes.type:detection OR exception-list-agnostic.attributes.type:rule_default)' - ); - }); -}); diff --git a/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts b/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts deleted file mode 100644 index cc9b46728cbc4..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ExceptionListFilter } from '@kbn/securitysolution-io-ts-list-types'; -import { isArray } from 'lodash'; -import { get } from 'lodash/fp'; -import { SavedObjectType } from '../types'; - -export const getGeneralFilters = ( - filters: ExceptionListFilter, - namespaceTypes: SavedObjectType[] -): string => { - return Object.keys(filters) - .map((filterKey) => { - const value = get(filterKey, filters); - if (isArray(value) || (value != null && value.trim() !== '')) { - const filtersByNamespace = namespaceTypes - .map((namespace) => { - const fieldToSearch = - filterKey === 'name' ? 'name.text' : filterKey === 'types' ? 'type' : filterKey; - return isArray(value) - ? value.map((val) => `${namespace}.attributes.${fieldToSearch}:${val}`).join(' OR ') - : `${namespace}.attributes.${fieldToSearch}:${value}`; - }) - .join(' OR '); - return `(${filtersByNamespace})`; - } else return null; - }) - .filter((item) => item != null) - .join(' AND '); -}; diff --git a/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts b/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts deleted file mode 100644 index df5bedc2d2b49..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { getIdsAndNamespaces } from '.'; - -describe('getIdsAndNamespaces', () => { - test('it returns empty arrays if no lists found', async () => { - const output = getIdsAndNamespaces({ - lists: [], - showDetection: false, - showEndpoint: false, - }); - - expect(output).toEqual({ ids: [], namespaces: [] }); - }); - - test('it returns all lists if "showDetection" and "showEndpoint" are "false"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: false, - showEndpoint: false, - }); - - expect(output).toEqual({ - ids: ['list_id', 'list_id_endpoint'], - namespaces: ['single', 'agnostic'], - }); - }); - - test('it returns only detections lists if "showDetection" is "true"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: true, - showEndpoint: false, - }); - - expect(output).toEqual({ - ids: ['list_id'], - namespaces: ['single'], - }); - }); - - test('it returns only endpoint lists if "showEndpoint" is "true"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: false, - showEndpoint: true, - }); - - expect(output).toEqual({ - ids: ['list_id_endpoint'], - namespaces: ['agnostic'], - }); - }); - - test('it returns only detection lists if both "showEndpoint" and "showDetection" are "true"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: true, - showEndpoint: true, - }); - - expect(output).toEqual({ - ids: ['list_id'], - namespaces: ['single'], - }); - }); -}); diff --git a/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts b/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts deleted file mode 100644 index bc18dff7d33e1..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { ExceptionListIdentifiers, NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; - -export const getIdsAndNamespaces = ({ - lists, - showDetection, - showEndpoint, -}: { - lists: ExceptionListIdentifiers[]; - showDetection: boolean; - showEndpoint: boolean; -}): { ids: string[]; namespaces: NamespaceType[] } => - lists - .filter((list) => { - if (showDetection) { - return list.type === 'detection'; - } else if (showEndpoint) { - return list.type === 'endpoint'; - } else { - return true; - } - }) - .reduce<{ ids: string[]; namespaces: NamespaceType[] }>( - (acc, { listId, namespaceType }) => ({ - ids: [...acc.ids, listId], - namespaces: [...acc.namespaces, namespaceType], - }), - { ids: [], namespaces: [] } - ); diff --git a/packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts b/packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts deleted file mode 100644 index 3e6cd312cb967..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; - -import { - exceptionListAgnosticSavedObjectType, - exceptionListSavedObjectType, - SavedObjectType, -} from '../types'; - -export const getSavedObjectType = ({ - namespaceType, -}: { - namespaceType: NamespaceType; -}): SavedObjectType => { - if (namespaceType === 'agnostic') { - return exceptionListAgnosticSavedObjectType; - } else { - return exceptionListSavedObjectType; - } -}; diff --git a/packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts b/packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts deleted file mode 100644 index ec09fc25bd772..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { NamespaceTypeArray } from '@kbn/securitysolution-io-ts-list-types'; - -import { SavedObjectType } from '../types'; -import { getSavedObjectType } from '../get_saved_object_type'; - -export const getSavedObjectTypes = ({ - namespaceType, -}: { - namespaceType: NamespaceTypeArray; -}): SavedObjectType[] => { - return namespaceType.map((singleNamespaceType) => - getSavedObjectType({ namespaceType: singleNamespaceType }) - ); -}; diff --git a/packages/kbn-securitysolution-list-utils/src/has_large_value_list/index.ts b/packages/kbn-securitysolution-list-utils/src/has_large_value_list/index.ts deleted file mode 100644 index ef774b5c8cf11..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/has_large_value_list/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { EntriesArray } from '@kbn/securitysolution-io-ts-list-types'; - -export const hasLargeValueList = (entries: EntriesArray): boolean => { - const found = entries.filter(({ type }) => type === 'list'); - return found.length > 0; -}; diff --git a/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts b/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts deleted file mode 100644 index fffcabbf41575..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts +++ /dev/null @@ -1,377 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - getMappingConflictsInfo, - fieldSupportsMatches, - hasWrongOperatorWithWildcard, - hasPartialCodeSignatureEntry, -} from '.'; - -describe('Helpers', () => { - describe('getMappingConflictsInfo', () => { - test('it return null if there are not conflicts', () => { - const field = { - name: 'field1', - type: 'string', - }; - const conflictsInfo = getMappingConflictsInfo(field); - - expect(conflictsInfo).toBeNull(); - }); - test('it groups ".ds-" data stream indices', () => { - const field = { - name: 'field1', - type: 'conflict', - conflictDescriptions: { - text: [ - '.ds-logs-default-2023.01.18-000001', - '.ds-logs-default-2023.01.18-000002', - '.ds-logs-tortilla.process-default-2022.11.20-000011', - '.ds-logs-tortilla.process-default-2022.11.20-000012', - '.ds-logs-tortilla.process-default-2022.11.20-000016', - ], - long: [ - '.ds-logs-default-2023.01.18-000004', - '.ds-logs-default-2023.01.18-000005', - 'partial-.ds-logs-gcp.audit-2021.12.22-000240', - 'partial-.ds-logs-gcp.audit-2021.12.22-000242', - ], - }, - }; - const conflictsInfo = getMappingConflictsInfo(field); - - expect(conflictsInfo).toEqual([ - { - type: 'text', - totalIndexCount: 5, - groupedIndices: [ - { name: 'logs-tortilla.process-default', count: 3 }, - { name: 'logs-default', count: 2 }, - ], - }, - { - type: 'long', - totalIndexCount: 4, - groupedIndices: [ - { name: 'logs-default', count: 2 }, - { name: 'logs-gcp.audit', count: 2 }, - ], - }, - ]); - }); - test('it groups old ".siem-" indices', () => { - const field = { - name: 'field1', - type: 'conflict', - conflictDescriptions: { - text: [ - '.siem-signals-default-000001', - '.siem-signals-default-000002', - '.siem-signals-default-000011', - '.siem-signals-default-000012', - ], - unmapped: [ - '.siem-signals-default-000004', - '.siem-signals-default-000005', - '.siem-signals-default-000240', - ], - }, - }; - const conflictsInfo = getMappingConflictsInfo(field); - - expect(conflictsInfo).toEqual([ - { - type: 'text', - totalIndexCount: 4, - groupedIndices: [{ name: '.siem-signals-default', count: 4 }], - }, - { - type: 'unmapped', - totalIndexCount: 3, - groupedIndices: [{ name: '.siem-signals-default', count: 3 }], - }, - ]); - }); - test('it groups mixed indices', () => { - const field = { - name: 'field1', - type: 'conflict', - conflictDescriptions: { - boolean: [ - '.ds-logs-default-2023.01.18-000001', - '.ds-logs-tortilla.process-default-2022.11.20-000011', - '.ds-logs-tortilla.process-default-2022.11.20-000012', - '.ds-logs-tortilla.process-default-2022.11.20-000016', - '.siem-signals-default-000001', - '.siem-signals-default-000002', - '.siem-signals-default-000012', - 'my-own-index-1', - 'my-own-index-2', - ], - unmapped: [ - '.siem-signals-default-000004', - 'partial-.ds-logs-gcp.audit-2021.12.22-000240', - 'partial-.ds-logs-gcp.audit-2021.12.22-000242', - 'my-own-index-3', - ], - }, - }; - const conflictsInfo = getMappingConflictsInfo(field); - - expect(conflictsInfo).toEqual([ - { - type: 'boolean', - totalIndexCount: 9, - groupedIndices: [ - { name: 'logs-tortilla.process-default', count: 3 }, - { name: '.siem-signals-default', count: 3 }, - { name: 'logs-default', count: 1 }, - { name: 'my-own-index-1', count: 1 }, - { name: 'my-own-index-2', count: 1 }, - ], - }, - { - type: 'unmapped', - totalIndexCount: 4, - groupedIndices: [ - { name: 'logs-gcp.audit', count: 2 }, - { name: '.siem-signals-default', count: 1 }, - { name: 'my-own-index-3', count: 1 }, - ], - }, - ]); - }); - }); - - describe('fieldSupportsMatches', () => { - test('it returns true if esTypes is keyword', () => { - expect( - fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['keyword'] }) - ).toBeTruthy(); - }); - - test('it returns true if one of the esTypes is kibana type string and another is not', () => { - expect( - fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['keyword', 'object'] }) - ).toBeTruthy(); - }); - - test('it returns true if one of the esTypes is keyword', () => { - expect( - fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['keyword', 'unmapped'] }) - ).toBeTruthy(); - }); - - test('it returns true if one of the esTypes is text', () => { - expect( - fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['text', 'unmapped'] }) - ).toBeTruthy(); - }); - - test('it returns true if all of the esTypes is map to kibana type string', () => { - expect( - fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['text', 'keyword'] }) - ).toBeTruthy(); - }); - - test('it returns false if none of the esTypes map to kibana type string', () => { - expect( - fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['bool', 'unmapped'] }) - ).toBeFalsy(); - }); - }); - describe('hasWrongOperatorWithWildcard', () => { - test('it returns true if there is at least one exception entry with a wildcard and the wrong operator', () => { - expect( - hasWrongOperatorWithWildcard([ - { - description: '', - name: '', - type: 'simple', - entries: [{ type: 'match', value: 'withwildcard*', field: '', operator: 'included' }], - }, - ]) - ).toBeTruthy(); - expect( - hasWrongOperatorWithWildcard([ - { - description: '', - name: '', - type: 'simple', - entries: [{ type: 'match', value: 'withwildcard?', field: '', operator: 'included' }], - }, - ]) - ).toBeTruthy(); - }); - - test('it returns true if there are entries joined with an OR that have a wildcard and the wrong operator', () => { - expect( - hasWrongOperatorWithWildcard([ - { - description: '', - name: '', - type: 'simple', - entries: [{ type: 'match', value: 'withwildcard?', field: '', operator: 'included' }], - }, - { - description: '', - name: '', - type: 'simple', - entries: [{ type: 'match', value: 'withwildcard?*', field: '', operator: 'included' }], - }, - ]) - ).toBeTruthy(); - }); - - test('it returns false if there are no exception entries with a wildcard and the wrong operator', () => { - expect( - hasWrongOperatorWithWildcard([ - { - description: '', - name: '', - type: 'simple', - entries: [ - { type: 'match', value: 'nowildcard', field: '', operator: 'excluded' }, - { type: 'wildcard', value: 'withwildcard*?', field: '', operator: 'included' }, - ], - }, - ]) - ).toBeFalsy(); - }); - - test('it returns true if there are nested entries with a wildcard and the wrong operator', () => { - expect( - hasWrongOperatorWithWildcard([ - { - description: '', - name: '', - type: 'simple', - entries: [ - { type: 'match', value: 'nowildcard', field: '', operator: 'excluded' }, - { - field: '', - type: 'nested', - entries: [{ type: 'match', value: 'wildcard?', field: '', operator: 'excluded' }], - }, - ], - }, - ]) - ).toBeTruthy(); - }); - }); - - describe('hasPartialCodeSignatureEntry', () => { - it('returns false if the entry has neither code signature subject name nor trusted field', () => { - expect( - hasPartialCodeSignatureEntry([ - { - description: '', - name: '', - type: 'simple', - os_types: ['windows'], - entries: [{ type: 'match', value: 'asdf', field: 'someField', operator: 'excluded' }], - }, - ]) - ).toBeFalsy(); - }); - it('returns true if the entry has code signature subject name but not trusted field', () => { - expect( - hasPartialCodeSignatureEntry([ - { - description: '', - name: '', - type: 'simple', - os_types: ['windows'], - entries: [ - { - type: 'match', - value: 'asdf', - field: 'process.code_signature.subject_name', - operator: 'excluded', - }, - ], - }, - ]) - ).toBeTruthy(); - }); - it('returns true if the entry has code signature trusted but not the subject name field', () => { - expect( - hasPartialCodeSignatureEntry([ - { - description: '', - name: '', - type: 'simple', - os_types: ['windows'], - entries: [ - { - type: 'match', - value: 'asdf', - field: 'process.code_signature.trusted', - operator: 'excluded', - }, - ], - }, - ]) - ).toBeTruthy(); - }); - it('returns false if the entry has both code signature subject name and trusted field', () => { - expect( - hasPartialCodeSignatureEntry([ - { - description: '', - name: '', - type: 'simple', - os_types: ['windows'], - entries: [ - { - type: 'match', - value: 'asdf', - field: 'process.code_signature.subject_name', - operator: 'excluded', - }, - { - type: 'match', - value: 'true', - field: 'process.code_signature.trusted', - operator: 'excluded', - }, - ], - }, - ]) - ).toBeFalsy(); - }); - it('returns false if the entry has both code signature team_id and trusted fields for mac os', () => { - expect( - hasPartialCodeSignatureEntry([ - { - description: '', - name: '', - type: 'simple', - os_types: ['macos'], - entries: [ - { - type: 'match', - value: 'asdf', - field: 'process.code_signature.team_id', - operator: 'excluded', - }, - { - type: 'match', - value: 'true', - field: 'process.code_signature.trusted', - operator: 'excluded', - }, - ], - }, - ]) - ).toBeFalsy(); - }); - }); -}); diff --git a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts deleted file mode 100644 index 8031cfba14f2d..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts +++ /dev/null @@ -1,1089 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { v4 as uuidv4 } from 'uuid'; -import { - addIdToItem, - removeIdFromItem, - validateHasWildcardWithWrongOperator, -} from '@kbn/securitysolution-utils'; -import { validate } from '@kbn/securitysolution-io-ts-utils'; -import { - CreateExceptionListItemSchema, - EntriesArray, - Entry, - EntryNested, - ExceptionListType, - ListSchema, - NamespaceType, - ListOperatorEnum as OperatorEnum, - ListOperatorTypeEnum as OperatorTypeEnum, - createExceptionListItemSchema, - entriesList, - entriesNested, - entry, - exceptionListItemSchema, - nestedEntryItem, - CreateRuleExceptionListItemSchema, - createRuleExceptionListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { - DataViewBase, - DataViewFieldBase, - getDataViewFieldSubtypeNested, - isDataViewFieldSubtypeNested, -} from '@kbn/es-query'; -import { castEsToKbnFieldTypeName, KBN_FIELD_TYPES } from '@kbn/field-types'; - -import { - ALL_OPERATORS, - EXCEPTION_OPERATORS_SANS_LISTS, - doesNotExistOperator, - existsOperator, - isNotOperator, - isOneOfOperator, - isOperator, - DETECTION_ENGINE_EXCEPTION_OPERATORS, - isNotOneOfOperator, - isInListOperator, - isNotInListOperator, - matchesOperator, - doesNotMatchOperator, -} from '../autocomplete_operators'; - -import { - BuilderEntry, - CreateExceptionListItemBuilderSchema, - DataViewField, - EmptyEntry, - EmptyNestedEntry, - ExceptionsBuilderExceptionItem, - ExceptionsBuilderReturnExceptionItem, - FormattedBuilderEntry, - OperatorOption, - SavedObjectType, -} from '../types'; - -export const isEntryNested = (item: BuilderEntry): item is EntryNested => { - return (item as EntryNested).entries != null; -}; - -export const filterExceptionItems = ( - exceptions: ExceptionsBuilderExceptionItem[] -): ExceptionsBuilderReturnExceptionItem[] => { - return exceptions.reduce((acc, exception) => { - const entries = exception.entries.reduce((nestedAcc, singleEntry) => { - const strippedSingleEntry = removeIdFromItem(singleEntry); - if (entriesNested.is(strippedSingleEntry)) { - const nestedEntriesArray = strippedSingleEntry.entries.filter((singleNestedEntry) => { - const noIdSingleNestedEntry = removeIdFromItem(singleNestedEntry); - const [validatedNestedEntry] = validate(noIdSingleNestedEntry, nestedEntryItem); - return validatedNestedEntry != null; - }); - const noIdNestedEntries = nestedEntriesArray.map((singleNestedEntry) => - removeIdFromItem(singleNestedEntry) - ); - - const [validatedNestedEntry] = validate( - { ...strippedSingleEntry, entries: noIdNestedEntries }, - entriesNested - ); - - if (validatedNestedEntry != null) { - return [...nestedAcc, { ...singleEntry, entries: nestedEntriesArray }]; - } - return nestedAcc; - } else { - const [validatedEntry] = validate(strippedSingleEntry, entry); - if (validatedEntry != null) { - return [...nestedAcc, singleEntry]; - } - return nestedAcc; - } - }, []); - - if (entries.length === 0) { - return acc; - } - - const item = { ...exception, entries }; - - if (exceptionListItemSchema.is(item)) { - return [...acc, item]; - } else if ( - createExceptionListItemSchema.is(item) || - createRuleExceptionListItemSchema.is(item) - ) { - const { meta, ...rest } = item; - const itemSansMetaId: CreateExceptionListItemSchema | CreateRuleExceptionListItemSchema = { - ...rest, - meta: undefined, - }; - return [...acc, itemSansMetaId]; - } else { - return acc; - } - }, []); -}; - -export const addIdToEntries = (entries: EntriesArray): EntriesArray => { - return entries.map((singleEntry) => { - if (singleEntry.type === 'nested') { - return addIdToItem({ - ...singleEntry, - entries: singleEntry.entries.map((nestedEntry) => addIdToItem(nestedEntry)), - }); - } else { - return addIdToItem(singleEntry); - } - }); -}; - -export const getNewExceptionItem = ({ - listId, - namespaceType, - name, -}: { - listId: string | undefined; - namespaceType: NamespaceType | undefined; - name: string; -}): CreateExceptionListItemBuilderSchema => { - return { - comments: [], - description: `Exception list item`, - entries: addIdToEntries([ - { - field: '', - operator: 'included', - type: 'match', - value: '', - }, - ]), - item_id: undefined, - list_id: listId, - meta: { - temporaryUuid: uuidv4(), - }, - name, - namespace_type: namespaceType, - tags: [], - type: 'simple', - }; -}; - -/** - * Returns the operator type, may not need this if using io-ts types - * - * @param item a single ExceptionItem entry - */ -export const getOperatorType = (item: BuilderEntry): OperatorTypeEnum => { - switch (item.type) { - case 'match': - return OperatorTypeEnum.MATCH; - case 'match_any': - return OperatorTypeEnum.MATCH_ANY; - case 'wildcard': - return OperatorTypeEnum.WILDCARD; - case 'list': - return OperatorTypeEnum.LIST; - default: - return OperatorTypeEnum.EXISTS; - } -}; - -/** - * Determines operator selection (is/is not/is one of, etc.) - * Default operator is "is" - * - * @param item a single ExceptionItem entry - */ -export const getExceptionOperatorSelect = (item: BuilderEntry): OperatorOption => { - if (item.type === 'nested') { - return isOperator; - } else { - const operatorType = getOperatorType(item); - const foundOperator = ALL_OPERATORS.find((operatorOption) => { - return item.operator === operatorOption.operator && operatorType === operatorOption.type; - }); - - return foundOperator != null ? foundOperator : isOperator; - } -}; - -/** - * Returns the fields corresponding value for an entry - * - * @param item a single ExceptionItem entry - */ -export const getEntryValue = (item: BuilderEntry): string | string[] | undefined => { - switch (item.type) { - case OperatorTypeEnum.MATCH: - case OperatorTypeEnum.MATCH_ANY: - case OperatorTypeEnum.WILDCARD: - return item.value; - case OperatorTypeEnum.EXISTS: - return undefined; - case OperatorTypeEnum.LIST: - return item.list.id; - default: - return undefined; - } -}; - -/** - * Determines whether an entire entry, exception item, or entry within a nested - * entry needs to be removed - * - * @param exceptionItem - * @param entryIndex index of given entry, for nested entries, this will correspond - * to their parent index - * @param nestedEntryIndex index of nested entry - * - */ -export const getUpdatedEntriesOnDelete = ( - exceptionItem: ExceptionsBuilderExceptionItem, - entryIndex: number, - nestedParentIndex: number | null -): ExceptionsBuilderExceptionItem => { - const itemOfInterest: BuilderEntry = - exceptionItem.entries[nestedParentIndex != null ? nestedParentIndex : entryIndex]; - - if (nestedParentIndex != null && itemOfInterest.type === OperatorTypeEnum.NESTED) { - const updatedEntryEntries = [ - ...itemOfInterest.entries.slice(0, entryIndex), - ...itemOfInterest.entries.slice(entryIndex + 1), - ]; - - if (updatedEntryEntries.length === 0) { - return { - ...exceptionItem, - entries: [ - ...exceptionItem.entries.slice(0, nestedParentIndex), - ...exceptionItem.entries.slice(nestedParentIndex + 1), - ], - }; - } else { - const { field } = itemOfInterest; - const updatedItemOfInterest: EntryNested | EmptyNestedEntry = { - entries: updatedEntryEntries, - field, - id: itemOfInterest.id != null ? itemOfInterest.id : `${entryIndex}`, - type: OperatorTypeEnum.NESTED, - }; - - return { - ...exceptionItem, - entries: [ - ...exceptionItem.entries.slice(0, nestedParentIndex), - updatedItemOfInterest, - ...exceptionItem.entries.slice(nestedParentIndex + 1), - ], - }; - } - } else { - return { - ...exceptionItem, - entries: [ - ...exceptionItem.entries.slice(0, entryIndex), - ...exceptionItem.entries.slice(entryIndex + 1), - ], - }; - } -}; - -/** - * Returns filtered index patterns based on the field - if a user selects to - * add nested entry, should only show nested fields, if item is the parent - * field of a nested entry, we only display the parent field - * - * @param patterns DataViewBase containing available fields on rule index - * @param item exception item entry - * set to add a nested field - */ -export const getFilteredIndexPatterns = ( - patterns: DataViewBase, - item: FormattedBuilderEntry -): DataViewBase => { - if (item.nested === 'child' && item.parent != null) { - // when user has selected a nested entry, only fields with the common parent are shown - return { - ...patterns, - fields: patterns.fields - .filter((indexField) => { - const subTypeNested = getDataViewFieldSubtypeNested(indexField); - const fieldHasCommonParentPath = - subTypeNested && - item.parent != null && - subTypeNested.nested.path === item.parent.parent.field; - - return fieldHasCommonParentPath; - }) - .map((f) => { - const [fieldNameWithoutParentPath] = f.name.split('.').slice(-1); - return { ...f, name: fieldNameWithoutParentPath }; - }), - }; - } else if (item.nested === 'parent' && item.field != null) { - // when user has selected a nested entry, right above it we show the common parent - return { ...patterns, fields: [item.field] }; - } else if (item.nested === 'parent' && item.field == null) { - // when user selects to add a nested entry, only nested fields are shown as options - return { - ...patterns, - fields: patterns.fields.filter((field) => isDataViewFieldSubtypeNested(field)), - }; - } else { - return patterns; - } -}; - -/** - * Determines proper entry update when user selects new field - * - * @param item - current exception item entry values - * @param newField - newly selected field - * - */ -export const getEntryOnFieldChange = ( - item: FormattedBuilderEntry, - newField: DataViewFieldBase -): { index: number; updatedEntry: BuilderEntry } => { - const { parent, entryIndex, nested } = item; - const newChildFieldValue = newField != null ? newField.name.split('.').slice(-1)[0] : ''; - - if (nested === 'parent') { - // For nested entries, when user first selects to add a nested - // entry, they first see a row similar to what is shown for when - // a user selects "exists", as soon as they make a selection - // we can now identify the 'parent' and 'child' this is where - // we first convert the entry into type "nested" - const subTypeNested = getDataViewFieldSubtypeNested(newField); - const newParentFieldValue = subTypeNested?.nested.path || ''; - - return { - index: entryIndex, - updatedEntry: { - entries: [ - addIdToItem({ - field: newChildFieldValue != null ? newChildFieldValue : '', - operator: isOperator.operator, - type: OperatorTypeEnum.MATCH, - value: '', - }), - ], - field: newParentFieldValue, - id: item.id, - type: OperatorTypeEnum.NESTED, - }, - }; - } else if (nested === 'child' && parent != null) { - return { - index: parent.parentIndex, - updatedEntry: { - ...parent.parent, - entries: [ - ...parent.parent.entries.slice(0, entryIndex), - { - field: newChildFieldValue != null ? newChildFieldValue : '', - id: item.id, - operator: isOperator.operator, - type: OperatorTypeEnum.MATCH, - value: '', - }, - ...parent.parent.entries.slice(entryIndex + 1), - ], - }, - }; - } else { - return { - index: entryIndex, - updatedEntry: { - field: newField != null ? newField.name : '', - id: item.id, - operator: isOperator.operator, - type: OperatorTypeEnum.MATCH, - value: '', - }, - }; - } -}; - -/** - * Determines proper entry update when user updates value - * when operator is of type "list" - * - * @param item - current exception item entry values - * @param newField - newly selected list - * - */ -export const getEntryOnListChange = ( - item: FormattedBuilderEntry, - newField: ListSchema -): { index: number; updatedEntry: BuilderEntry } => { - const { entryIndex, field, operator } = item; - const { id, type } = newField; - - return { - index: entryIndex, - updatedEntry: { - field: field != null ? field.name : '', - id: item.id, - list: { id, type }, - operator: operator.operator, - type: OperatorTypeEnum.LIST, - }, - }; -}; - -/** - * Determines proper entry update when user updates value - * when operator is of type "match_any" - * - * @param item - current exception item entry values - * @param newField - newly entered value - * - */ -export const getEntryOnMatchAnyChange = ( - item: FormattedBuilderEntry, - newField: string[] -): { index: number; updatedEntry: BuilderEntry } => { - const { nested, parent, entryIndex, field, operator } = item; - - if (nested != null && parent != null) { - const fieldName = field != null ? field.name.split('.').slice(-1)[0] : ''; - - return { - index: parent.parentIndex, - updatedEntry: { - ...parent.parent, - entries: [ - ...parent.parent.entries.slice(0, entryIndex), - { - field: fieldName, - id: item.id, - operator: operator.operator, - type: OperatorTypeEnum.MATCH_ANY, - value: newField, - }, - ...parent.parent.entries.slice(entryIndex + 1), - ], - }, - }; - } else { - return { - index: entryIndex, - updatedEntry: { - field: field != null ? field.name : '', - id: item.id, - operator: operator.operator, - type: OperatorTypeEnum.MATCH_ANY, - value: newField, - }, - }; - } -}; - -/** - * Determines proper entry update when user updates value - * when operator is of type "match" - * - * @param item - current exception item entry values - * @param newField - newly entered value - * - */ -export const getEntryOnMatchChange = ( - item: FormattedBuilderEntry, - newField: string -): { index: number; updatedEntry: BuilderEntry } => { - const { nested, parent, entryIndex, field, operator } = item; - - if (nested != null && parent != null) { - const fieldName = field != null ? field.name.split('.').slice(-1)[0] : ''; - - return { - index: parent.parentIndex, - updatedEntry: { - ...parent.parent, - entries: [ - ...parent.parent.entries.slice(0, entryIndex), - { - field: fieldName, - id: item.id, - operator: operator.operator, - type: OperatorTypeEnum.MATCH, - value: newField, - }, - ...parent.parent.entries.slice(entryIndex + 1), - ], - }, - }; - } else { - return { - index: entryIndex, - updatedEntry: { - field: field != null ? field.name : '', - id: item.id, - operator: operator.operator, - type: OperatorTypeEnum.MATCH, - value: newField, - }, - }; - } -}; - -/** - * Determines proper entry update when user updates value - * when operator is of type "wildcard" - * - * @param item - current exception item entry values - * @param newField - newly entered value - * - */ -export const getEntryOnWildcardChange = ( - item: FormattedBuilderEntry, - newField: string -): { index: number; updatedEntry: BuilderEntry } => { - const { nested, parent, entryIndex, field, operator } = item; - - if (nested != null && parent != null) { - const fieldName = field != null ? field.name.split('.').slice(-1)[0] : ''; - - return { - index: parent.parentIndex, - updatedEntry: { - ...parent.parent, - entries: [ - ...parent.parent.entries.slice(0, entryIndex), - { - field: fieldName, - id: item.id, - operator: operator.operator, - type: OperatorTypeEnum.WILDCARD, - value: newField, - }, - ...parent.parent.entries.slice(entryIndex + 1), - ], - }, - }; - } else { - return { - index: entryIndex, - updatedEntry: { - field: field != null ? field.name : '', - id: item.id, - operator: operator.operator, - type: OperatorTypeEnum.WILDCARD, - value: newField, - }, - }; - } -}; - -/** - * On operator change, determines whether value needs to be cleared or not - * - * @param field - * @param selectedOperator - * @param currentEntry - * - */ -export const getEntryFromOperator = ( - selectedOperator: OperatorOption, - currentEntry: FormattedBuilderEntry -): Entry & { id?: string } => { - const isSameOperatorType = currentEntry.operator.type === selectedOperator.type; - const fieldValue = currentEntry.field != null ? currentEntry.field.name : ''; - switch (selectedOperator.type) { - case 'match': - return { - field: fieldValue, - id: currentEntry.id, - operator: selectedOperator.operator, - type: OperatorTypeEnum.MATCH, - value: - isSameOperatorType && typeof currentEntry.value === 'string' ? currentEntry.value : '', - }; - case 'match_any': - return { - field: fieldValue, - id: currentEntry.id, - operator: selectedOperator.operator, - type: OperatorTypeEnum.MATCH_ANY, - value: isSameOperatorType && Array.isArray(currentEntry.value) ? currentEntry.value : [], - }; - case 'list': - return { - field: fieldValue, - id: currentEntry.id, - list: { id: '', type: 'ip' }, - operator: selectedOperator.operator, - type: OperatorTypeEnum.LIST, - }; - case 'wildcard': - return { - field: fieldValue, - id: currentEntry.id, - operator: selectedOperator.operator, - type: OperatorTypeEnum.WILDCARD, - value: - isSameOperatorType && typeof currentEntry.value === 'string' ? currentEntry.value : '', - }; - default: - return { - field: fieldValue, - id: currentEntry.id, - operator: selectedOperator.operator, - type: OperatorTypeEnum.EXISTS, - }; - } -}; - -/** - * Determines proper entry update when user selects new operator - * - * @param item - current exception item entry values - * @param newOperator - newly selected operator - * - */ -export const getEntryOnOperatorChange = ( - item: FormattedBuilderEntry, - newOperator: OperatorOption -): { updatedEntry: BuilderEntry; index: number } => { - const { parent, entryIndex, field, nested } = item; - const newEntry = getEntryFromOperator(newOperator, item); - - if (!entriesList.is(newEntry) && nested != null && parent != null) { - return { - index: parent.parentIndex, - updatedEntry: { - ...parent.parent, - entries: [ - ...parent.parent.entries.slice(0, entryIndex), - { - ...newEntry, - field: field != null ? field.name.split('.').slice(-1)[0] : '', - }, - ...parent.parent.entries.slice(entryIndex + 1), - ], - }, - }; - } else { - return { index: entryIndex, updatedEntry: newEntry }; - } -}; - -export const isKibanaStringType = (type: string) => { - const kbnFieldType = castEsToKbnFieldTypeName(type); - return kbnFieldType === KBN_FIELD_TYPES.STRING; -}; - -export const fieldSupportsMatches = (field: DataViewFieldBase) => { - return field.esTypes?.some(isKibanaStringType); -}; - -/** - * Determines which operators to make available - * - * @param item - * @param listType - * @param isBoolean - * @param includeValueListOperators whether or not to include the 'is in list' and 'is not in list' operators - */ -export const getOperatorOptions = ( - item: FormattedBuilderEntry, - listType: ExceptionListType, - isBoolean: boolean, - includeValueListOperators = true -): OperatorOption[] => { - if (item.nested === 'parent' || item.field == null) { - return [isOperator]; - } else if (listType === 'endpoint') { - if (isBoolean) { - return [isOperator]; - } else { - return fieldSupportsMatches(item.field) - ? [isOperator, isOneOfOperator, matchesOperator, doesNotMatchOperator] - : [isOperator, isOneOfOperator]; - } - } else if (item.nested != null && listType === 'detection') { - return isBoolean ? [isOperator, existsOperator] : [isOperator, isOneOfOperator, existsOperator]; - } else if (isBoolean) { - return [isOperator, isNotOperator, existsOperator, doesNotExistOperator]; - } else if (!includeValueListOperators) { - return fieldSupportsMatches(item.field) - ? EXCEPTION_OPERATORS_SANS_LISTS - : [ - isOperator, - isNotOperator, - isOneOfOperator, - isNotOneOfOperator, - existsOperator, - doesNotExistOperator, - ]; - } else { - return listType === 'detection' - ? fieldSupportsMatches(item.field) - ? DETECTION_ENGINE_EXCEPTION_OPERATORS - : [ - isOperator, - isNotOperator, - isOneOfOperator, - isNotOneOfOperator, - existsOperator, - doesNotExistOperator, - isInListOperator, - isNotInListOperator, - ] - : ALL_OPERATORS; - } -}; - -/** - * Fields of type 'text' do not generate autocomplete values, we want - * to find it's corresponding keyword type (if available) which does - * generate autocomplete values - * - * @param fields DataViewFieldBase fields - * @param selectedField the field name that was selected - * @param isTextType we only want a corresponding keyword field if - * the selected field is of type 'text' - * - */ -export const getCorrespondingKeywordField = ({ - fields, - selectedField, -}: { - fields: DataViewFieldBase[]; - selectedField: string | undefined; -}): DataViewFieldBase | undefined => { - const selectedFieldBits = - selectedField != null && selectedField !== '' ? selectedField.split('.') : []; - const selectedFieldIsTextType = selectedFieldBits.slice(-1)[0] === 'text'; - - if (selectedFieldIsTextType && selectedFieldBits.length > 0) { - const keywordField = selectedFieldBits.slice(0, selectedFieldBits.length - 1).join('.'); - const [foundKeywordField] = fields.filter( - ({ name }) => keywordField !== '' && keywordField === name - ); - return foundKeywordField; - } - - return undefined; -}; - -/** - * Formats the entry into one that is easily usable for the UI, most of the - * complexity was introduced with nested fields - * - * @param patterns DataViewBase containing available fields on rule index - * @param item exception item entry - * @param itemIndex entry index - * @param parent nested entries hold copy of their parent for use in various logic - * @param parentIndex corresponds to the entry index, this might seem obvious, but - * was added to ensure that nested items could be identified with their parent entry - * @param allowCustomFieldOptions determines if field must be found to match in indexPattern or not - */ -export const getFormattedBuilderEntry = ( - indexPattern: DataViewBase, - item: BuilderEntry, - itemIndex: number, - parent: EntryNested | undefined, - parentIndex: number | undefined, - allowCustomFieldOptions: boolean -): FormattedBuilderEntry => { - const { fields } = indexPattern; - const field = parent != null ? `${parent.field}.${item.field}` : item.field; - const [foundField] = fields.filter(({ name }) => field != null && field === name); - const correspondingKeywordField = getCorrespondingKeywordField({ - fields, - selectedField: field, - }); - - if (parent != null && parentIndex != null) { - return { - correspondingKeywordField, - entryIndex: itemIndex, - field: - foundField != null - ? { ...foundField, name: foundField.name.split('.').slice(-1)[0] } - : foundField, - id: item.id != null ? item.id : `${itemIndex}`, - nested: 'child', - operator: getExceptionOperatorSelect(item), - parent: { parent, parentIndex }, - value: getEntryValue(item), - }; - } else { - const fieldToUse = allowCustomFieldOptions - ? foundField ?? { name: item.field, type: 'keyword' } - : foundField; - - return { - correspondingKeywordField, - entryIndex: itemIndex, - field: fieldToUse, - id: item.id != null ? item.id : `${itemIndex}`, - nested: undefined, - operator: getExceptionOperatorSelect(item), - parent: undefined, - value: getEntryValue(item), - }; - } -}; - -/** - * Formats the entries to be easily usable for the UI, most of the - * complexity was introduced with nested fields - * - * @param patterns DataViewBase containing available fields on rule index - * @param entries exception item entries - * @param allowCustomFieldOptions determines if field must be found to match in indexPattern or not - * @param parent nested entries hold copy of their parent for use in various logic - * @param parentIndex corresponds to the entry index, this might seem obvious, but - * was added to ensure that nested items could be identified with their parent entry - */ -export const getFormattedBuilderEntries = ( - indexPattern: DataViewBase, - entries: BuilderEntry[], - allowCustomFieldOptions: boolean, - parent?: EntryNested, - parentIndex?: number -): FormattedBuilderEntry[] => { - return entries.reduce((acc, item, index) => { - const isNewNestedEntry = item.type === 'nested' && item.entries.length === 0; - if (item.type !== 'nested' && !isNewNestedEntry) { - const newItemEntry: FormattedBuilderEntry = getFormattedBuilderEntry( - indexPattern, - item, - index, - parent, - parentIndex, - allowCustomFieldOptions - ); - return [...acc, newItemEntry]; - } else { - const parentEntry: FormattedBuilderEntry = { - correspondingKeywordField: undefined, - entryIndex: index, - field: isNewNestedEntry - ? undefined - : // This type below is really a FieldSpec type from "src/plugins/data/common/index_patterns/fields/types.ts", we cast it here to keep using the DataViewFieldBase interface - ({ - aggregatable: false, - esTypes: ['nested'], - name: item.field != null ? item.field : '', - searchable: false, - type: 'string', - } as DataViewFieldBase), - id: item.id != null ? item.id : `${index}`, - nested: 'parent', - operator: isOperator, - parent: undefined, - value: undefined, - }; - - // User has selected to add a nested field, but not yet selected the field - if (isNewNestedEntry) { - return [...acc, parentEntry]; - } - - if (isEntryNested(item)) { - const nestedItems = getFormattedBuilderEntries( - indexPattern, - item.entries, - allowCustomFieldOptions, - item, - index - ); - - return [...acc, parentEntry, ...nestedItems]; - } - - return [...acc]; - } - }, []); -}; - -export const getDefaultEmptyEntry = (): EmptyEntry => ({ - field: '', - id: uuidv4(), - operator: OperatorEnum.INCLUDED, - type: OperatorTypeEnum.MATCH, - value: '', -}); - -export const getDefaultNestedEmptyEntry = (): EmptyNestedEntry => ({ - entries: [], - field: '', - id: uuidv4(), - type: OperatorTypeEnum.NESTED, -}); - -export const containsValueListEntry = (items: ExceptionsBuilderExceptionItem[]): boolean => - items.some((item) => item.entries.some(({ type }) => type === OperatorTypeEnum.LIST)); - -export const buildShowActiveExceptionsFilter = (savedObjectPrefix: SavedObjectType[]): string => { - const now = new Date().toISOString(); - const filters = savedObjectPrefix.map( - (prefix) => - `${prefix}.attributes.expire_time > "${now}" OR NOT ${prefix}.attributes.expire_time: *` - ); - return filters.join(','); -}; - -export const buildShowExpiredExceptionsFilter = (savedObjectPrefix: SavedObjectType[]): string => { - const now = new Date().toISOString(); - const filters = savedObjectPrefix.map((prefix) => `${prefix}.attributes.expire_time <= "${now}"`); - return filters.join(','); -}; - -const getIndexGroupName = (indexName: string): string => { - // Check whether it is a Data Stream index - const dataStreamExp = /.ds-(.*?)-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-[0-9]{6}/; - let result = indexName.match(dataStreamExp); - if (result && result.length === 2) { - return result[1]; - } - - // Check whether it is an old '.siem' index group - const siemSignalsExp = /.siem-(.*?)-[0-9]{6}/; - result = indexName.match(siemSignalsExp); - if (result && result.length === 2) { - return `.siem-${result[1]}`; - } - - // Otherwise return index name - return indexName; -}; - -export interface FieldConflictsInfo { - /** - * Kibana field type - */ - type: string; - /** - * Total count of the indices of this type - */ - totalIndexCount: number; - /** - * Grouped indices info - */ - groupedIndices: Array<{ - /** - * Index group name (like '.ds-...' or '.siem-signals-...') - */ - name: string; - /** - * Count of indices in the group - */ - count: number; - }>; -} - -export const getMappingConflictsInfo = (field: DataViewField): FieldConflictsInfo[] | null => { - if (!field.conflictDescriptions) { - return null; - } - const conflicts: FieldConflictsInfo[] = []; - for (const [key, value] of Object.entries(field.conflictDescriptions)) { - const groupedIndices: Array<{ - name: string; - count: number; - }> = []; - - // Group indices and calculate count of indices in each group - const groupedInfo: { [key: string]: number } = {}; - value.forEach((index) => { - const groupName = getIndexGroupName(index); - if (!groupedInfo[groupName]) { - groupedInfo[groupName] = 0; - } - groupedInfo[groupName]++; - }); - for (const [name, count] of Object.entries(groupedInfo)) { - groupedIndices.push({ - name, - count, - }); - } - - // Sort groups by the indices count - groupedIndices.sort((group1, group2) => { - return group2.count - group1.count; - }); - - conflicts.push({ - type: key, - totalIndexCount: value.length, - groupedIndices, - }); - } - return conflicts; -}; - -/** - * Given an exceptions list, determine if any entries have an "IS" operator with a wildcard value - */ -export const hasWrongOperatorWithWildcard = ( - items: ExceptionsBuilderReturnExceptionItem[] -): boolean => { - // flattens array of multiple entries added with OR - const multipleEntries = items.flatMap((item) => item.entries); - // flattens nested entries - const allEntries = multipleEntries.flatMap((item) => { - if (item.type === 'nested') { - return item.entries; - } - return item; - }); - - return allEntries.some((e) => { - if (e.type !== 'list' && 'value' in e) { - return validateHasWildcardWithWrongOperator({ - operator: e.type, - value: e.value, - }); - } - }); -}; - -/** - * Event filters helper where given an exceptions list, - * determine if both 'subject_name' and 'trusted' are - * included in an entry with 'code_signature' - */ -export const hasPartialCodeSignatureEntry = ( - items: ExceptionsBuilderReturnExceptionItem[] -): boolean => { - const { os_types: os = ['windows'], entries = [] } = items[0] || {}; - let name = false; - let trusted = false; - - for (const e of entries) { - if (e.type === 'nested' && e.field === 'process.Ext.code_signature') { - const includesNestedName = e.entries.some( - (nestedEntry) => nestedEntry.field === 'subject_name' - ); - const includesNestedTrusted = e.entries.some( - (nestedEntry) => nestedEntry.field === 'trusted' - ); - if (includesNestedName !== includesNestedTrusted) { - return true; - } - } else if ( - e.field === 'process.code_signature.subject_name' || - (os.includes('macos') && e.field === 'process.code_signature.team_id') - ) { - name = true; - } else if (e.field === 'process.code_signature.trusted') { - trusted = true; - } - } - return name !== trusted; -}; diff --git a/packages/kbn-securitysolution-list-utils/src/types/index.ts b/packages/kbn-securitysolution-list-utils/src/types/index.ts deleted file mode 100644 index 97098af88caf4..0000000000000 --- a/packages/kbn-securitysolution-list-utils/src/types/index.ts +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { DataViewFieldBase } from '@kbn/es-query'; -import type { - CreateExceptionListItemSchema, - CreateRuleExceptionListItemSchema, - Entry, - EntryExists, - EntryMatch, - EntryMatchAny, - EntryMatchWildcard, - EntryNested, - ExceptionListItemSchema, - ListOperatorEnum as OperatorEnum, - ListOperatorTypeEnum as OperatorTypeEnum, - NamespaceType, -} from '@kbn/securitysolution-io-ts-list-types'; -import { - EXCEPTION_LIST_NAMESPACE, - EXCEPTION_LIST_NAMESPACE_AGNOSTIC, -} from '@kbn/securitysolution-list-constants'; - -export interface DataViewField extends DataViewFieldBase { - conflictDescriptions?: Record; -} - -export interface OperatorOption { - message: string; - value: string; - operator: OperatorEnum; - type: OperatorTypeEnum; -} - -export interface FormattedBuilderEntry { - id: string; - field: DataViewField | undefined; - operator: OperatorOption; - value: string | string[] | undefined; - nested: 'parent' | 'child' | undefined; - entryIndex: number; - parent: { parent: BuilderEntryNested; parentIndex: number } | undefined; - correspondingKeywordField: DataViewFieldBase | undefined; -} - -export interface EmptyEntry { - id: string; - field: string | undefined; - operator: OperatorEnum; - type: OperatorTypeEnum.MATCH | OperatorTypeEnum.MATCH_ANY | OperatorTypeEnum.WILDCARD; - value: string | string[] | undefined; -} - -export interface EmptyListEntry { - id: string; - field: string | undefined; - operator: OperatorEnum; - type: OperatorTypeEnum.LIST; - list: { id: string | undefined; type: string | undefined }; -} - -export interface EmptyNestedEntry { - id: string; - field: string | undefined; - type: OperatorTypeEnum.NESTED; - entries: Array< - | (EntryMatch & { id?: string }) - | (EntryMatchAny & { id?: string }) - | (EntryMatchWildcard & { id?: string }) - | (EntryExists & { id?: string }) - >; -} - -export type BuilderEntry = - | (Entry & { id?: string }) - | EmptyListEntry - | EmptyEntry - | BuilderEntryNested - | EmptyNestedEntry; - -export type BuilderEntryNested = Omit & { - id?: string; - entries: Array< - | (EntryMatch & { id?: string }) - | (EntryMatchAny & { id?: string }) - | (EntryMatchWildcard & { id?: string }) - | (EntryExists & { id?: string }) - >; -}; - -export type ExceptionListItemBuilderSchema = Omit & { - entries: BuilderEntry[]; -}; - -export type CreateExceptionListItemBuilderSchema = Omit< - CreateExceptionListItemSchema, - 'meta' | 'entries' | 'list_id' | 'namespace_type' -> & { - meta: { temporaryUuid: string }; - entries: BuilderEntry[]; - list_id: string | undefined; - namespace_type: NamespaceType | undefined; -}; - -export type ExceptionsBuilderExceptionItem = - | ExceptionListItemBuilderSchema - | CreateExceptionListItemBuilderSchema; - -export type ExceptionsBuilderReturnExceptionItem = - | ExceptionListItemSchema - | CreateExceptionListItemSchema - | CreateRuleExceptionListItemSchema; - -export const exceptionListSavedObjectType = EXCEPTION_LIST_NAMESPACE; -export const exceptionListAgnosticSavedObjectType = EXCEPTION_LIST_NAMESPACE_AGNOSTIC; -export type SavedObjectType = - | typeof EXCEPTION_LIST_NAMESPACE - | typeof EXCEPTION_LIST_NAMESPACE_AGNOSTIC; diff --git a/packages/kbn-securitysolution-list-utils/tsconfig.json b/packages/kbn-securitysolution-list-utils/tsconfig.json deleted file mode 100644 index d75eb1f98314c..0000000000000 --- a/packages/kbn-securitysolution-list-utils/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/es-query", - "@kbn/i18n", - "@kbn/securitysolution-io-ts-list-types", - "@kbn/securitysolution-io-ts-utils", - "@kbn/securitysolution-list-constants", - "@kbn/securitysolution-utils", - "@kbn/field-types" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts deleted file mode 100644 index ce05117c33082..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Create list API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { - ListId, - ListName, - ListDescription, - ListType, - ListMetadata, -} from '../model/list_common.gen'; -import { List } from '../model/list_schemas.gen'; - -export type CreateListRequestBody = z.infer; -export const CreateListRequestBody = z.object({ - id: ListId.optional(), - name: ListName, - description: ListDescription, - type: ListType, - serializer: z.string().optional(), - deserializer: z.string().optional(), - meta: ListMetadata.optional(), - version: z.number().int().min(1).optional().default(1), -}); -export type CreateListRequestBodyInput = z.input; - -export type CreateListResponse = z.infer; -export const CreateListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml deleted file mode 100644 index 191e973beba61..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml +++ /dev/null @@ -1,81 +0,0 @@ -openapi: 3.0.0 -info: - title: Create list API endpoint - version: '2023-10-31' -paths: - /api/lists: - post: - x-labels: [serverless, ess] - operationId: CreateList - x-codegen-enabled: true - summary: Create a list - description: Create a new list. - requestBody: - description: List's properties - required: true - content: - application/json: - schema: - type: object - properties: - id: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - name: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListName' - description: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListDescription' - type: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListType' - serializer: - type: string - deserializer: - type: string - meta: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListMetadata' - version: - type: integer - minimum: 1 - default: 1 - required: - - name - - description - - type - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 409: - description: List already exists response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts b/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts deleted file mode 100644 index 13b5248b92704..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Create list DS API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -export type CreateListIndexResponse = z.infer; -export const CreateListIndexResponse = z.object({ - acknowledged: z.boolean(), -}); diff --git a/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml b/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml deleted file mode 100644 index c775a9c7d873f..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml +++ /dev/null @@ -1,55 +0,0 @@ -openapi: 3.0.0 -info: - title: Create list DS API endpoint - version: '2023-10-31' -paths: - /api/lists/index: - post: - x-labels: [serverless, ess] - operationId: CreateListIndex - x-codegen-enabled: true - summary: Create list data streams - description: Create `.lists` and `.items` data streams in the relevant space. - responses: - 200: - description: Successful response - content: - application/json: - schema: - type: object - properties: - acknowledged: - type: boolean - required: [acknowledged] - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 409: - description: List data stream exists response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts deleted file mode 100644 index 4ebafd6568571..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Create list item API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { ListItemId, ListId, ListItemValue, ListItemMetadata } from '../model/list_common.gen'; -import { ListItem } from '../model/list_schemas.gen'; - -export type CreateListItemRequestBody = z.infer; -export const CreateListItemRequestBody = z.object({ - id: ListItemId.optional(), - list_id: ListId, - value: ListItemValue, - meta: ListItemMetadata.optional(), - /** - * Determines when changes made by the request are made visible to search - */ - refresh: z.enum(['true', 'false', 'wait_for']).optional(), -}); -export type CreateListItemRequestBodyInput = z.input; - -export type CreateListItemResponse = z.infer; -export const CreateListItemResponse = ListItem; diff --git a/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml deleted file mode 100644 index 01121d0143925..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml +++ /dev/null @@ -1,82 +0,0 @@ -openapi: 3.0.0 -info: - title: Create list item API endpoint - version: '2023-10-31' -paths: - /api/lists/items: - post: - x-labels: [serverless, ess] - operationId: CreateListItem - x-codegen-enabled: true - summary: Create a list item - description: | - Create a list item and associate it with the specified list. - - All list items in the same list must be the same type. For example, each list item in an `ip` list must define a specific IP address. - > info - > Before creating a list item, you must create a list. - requestBody: - description: List item's properties - required: true - content: - application/json: - schema: - type: object - properties: - id: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemId' - list_id: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - value: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemValue' - meta: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemMetadata' - refresh: - type: string - enum: - - 'true' - - 'false' - - wait_for - description: Determines when changes made by the request are made visible to search - required: - - list_id - - value - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 409: - description: List item already exists response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.ts deleted file mode 100644 index 109e6c58a1163..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Delete list API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; -import { BooleanFromString } from '@kbn/zod-helpers'; - -import { ListId } from '../model/list_common.gen'; -import { List } from '../model/list_schemas.gen'; - -export type DeleteListRequestQuery = z.infer; -export const DeleteListRequestQuery = z.object({ - /** - * List's `id` value - */ - id: ListId, - deleteReferences: BooleanFromString.optional().default(false), - ignoreReferences: BooleanFromString.optional().default(false), -}); -export type DeleteListRequestQueryInput = z.input; - -export type DeleteListResponse = z.infer; -export const DeleteListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml deleted file mode 100644 index 7098753636379..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml +++ /dev/null @@ -1,73 +0,0 @@ -openapi: 3.0.0 -info: - title: Delete list API endpoint - version: '2023-10-31' -paths: - /api/lists: - delete: - x-labels: [serverless, ess] - operationId: DeleteList - x-codegen-enabled: true - summary: Delete a list - description: | - Delete a list using the list ID. - > info - > When you delete a list, all of its list items are also deleted. - parameters: - - name: id - in: query - required: true - description: List's `id` value - schema: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - - name: deleteReferences - in: query - required: false - schema: - type: boolean - default: false - - name: ignoreReferences - in: query - required: false - schema: - type: boolean - default: false - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts b/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts deleted file mode 100644 index 314c1e81bc6a9..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Delete list DS API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -export type DeleteListIndexResponse = z.infer; -export const DeleteListIndexResponse = z.object({ - acknowledged: z.boolean(), -}); diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml b/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml deleted file mode 100644 index 4f4b0f00e8817..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml +++ /dev/null @@ -1,55 +0,0 @@ -openapi: 3.0.0 -info: - title: Delete list DS API endpoint - version: '2023-10-31' -paths: - /api/lists/index: - delete: - x-labels: [serverless, ess] - operationId: DeleteListIndex - x-codegen-enabled: true - summary: Delete list data streams - description: Delete the `.lists` and `.items` data streams. - responses: - 200: - description: Successful response - content: - application/json: - schema: - type: object - properties: - acknowledged: - type: boolean - required: [acknowledged] - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List data stream not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml deleted file mode 100644 index 28913259387dd..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml +++ /dev/null @@ -1,82 +0,0 @@ -openapi: 3.0.0 -info: - title: Delete list item API endpoint - version: '2023-10-31' -paths: - /api/lists/items: - delete: - x-labels: [serverless, ess] - operationId: DeleteListItem - x-codegen-enabled: true - summary: Delete a list item - description: Delete a list item using its `id`, or its `list_id` and `value` fields. - parameters: - - name: id - in: query - required: false - description: Required if `list_id` and `value` are not specified - schema: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - - name: list_id - in: query - required: false - description: Required if `id` is not specified - schema: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - - name: value - in: query - required: false - description: Required if `id` is not specified - schema: - type: string - - name: refresh - in: query - required: false - description: Determines when changes made by the request are made visible to search - schema: - type: string - enum: ['true', 'false', 'wait_for'] - default: 'false' - responses: - 200: - description: Successful response - content: - application/json: - schema: - oneOf: - - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' - - type: array - items: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List item not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.gen.ts b/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.gen.ts deleted file mode 100644 index 4e514abefccc2..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.gen.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Export list items API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { ListId } from '../model/list_common.gen'; - -export type ExportListItemsRequestQuery = z.infer; -export const ExportListItemsRequestQuery = z.object({ - /** - * List's id to export - */ - list_id: ListId, -}); -export type ExportListItemsRequestQueryInput = z.input; diff --git a/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.schema.yaml b/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.schema.yaml deleted file mode 100644 index 8d185a23b64c9..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.schema.yaml +++ /dev/null @@ -1,60 +0,0 @@ -openapi: 3.0.0 -info: - title: Export list items API endpoint - version: '2023-10-31' -paths: - /api/lists/items/_export: - post: - x-labels: [serverless, ess] - operationId: ExportListItems - x-codegen-enabled: true - summary: Export list items - description: Export list item values from the specified list. - parameters: - - name: list_id - in: query - required: true - description: List's id to export - schema: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - responses: - 200: - description: Successful response - content: - application/ndjson: - schema: - type: string - format: binary - description: A `.txt` file containing list items from the specified list - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/index.ts b/packages/kbn-securitysolution-lists-common/api/index.ts deleted file mode 100644 index 27c70d1628109..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './model/list_common.gen'; -export * from './model/list_schemas.gen'; -export * from './create_list_index/create_list_index.gen'; -export * from './create_list_item/create_list_item.gen'; -export * from './create_list/create_list.gen'; -export * from './delete_list_index/delete_list_index.gen'; -export * from './delete_list_item/delete_list_item.gen'; -export * from './delete_list/delete_list.gen'; -export * from './find_list_items/find_list_items.gen'; -export * from './find_lists/find_lists.gen'; -export * from './export_list_items/export_list_items.gen'; -export * from './import_list_items/import_list_items.gen'; -export * from './patch_list_item/patch_list_item.gen'; -export * from './patch_list/patch_list.gen'; -export * from './read_list_index/read_list_index.gen'; -export * from './read_list_item/read_list_item.gen'; -export * from './read_list/read_list.gen'; -export * from './update_list_item/update_list_item.gen'; -export * from './update_list/update_list.gen'; diff --git a/packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml b/packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml deleted file mode 100644 index 6fb160105bb5a..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml +++ /dev/null @@ -1,59 +0,0 @@ -openapi: 3.0.0 -info: - title: Common List Attributes - version: 'not applicable' -paths: {} -components: - schemas: - ListId: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - - ListType: - type: string - enum: - - binary - - boolean - - byte - - date - - date_nanos - - date_range - - double - - double_range - - float - - float_range - - geo_point - - geo_shape - - half_float - - integer - - integer_range - - ip - - ip_range - - keyword - - long - - long_range - - shape - - short - - text - - ListName: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - - ListDescription: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - - ListMetadata: - type: object - additionalProperties: true - - ListItemId: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - - ListItemValue: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - - ListItemDescription: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - - ListItemMetadata: - type: object - additionalProperties: true diff --git a/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts deleted file mode 100644 index d7c955e6daac3..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Patch list API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { ListId, ListName, ListDescription, ListMetadata } from '../model/list_common.gen'; -import { List } from '../model/list_schemas.gen'; - -export type PatchListRequestBody = z.infer; -export const PatchListRequestBody = z.object({ - id: ListId, - name: ListName.optional(), - description: ListDescription.optional(), - meta: ListMetadata.optional(), - version: z.number().int().min(1).optional(), - _version: z.string().optional(), -}); -export type PatchListRequestBodyInput = z.input; - -export type PatchListResponse = z.infer; -export const PatchListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml deleted file mode 100644 index b98b34e6347eb..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml +++ /dev/null @@ -1,74 +0,0 @@ -openapi: 3.0.0 -info: - title: Patch list API endpoint - version: '2023-10-31' -paths: - /api/lists: - patch: - x-labels: [serverless, ess] - operationId: PatchList - x-codegen-enabled: true - summary: Patch a list - description: Update specific fields of an existing list using the list ID. - requestBody: - description: List's properties - required: true - content: - application/json: - schema: - type: object - properties: - id: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - name: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListName' - description: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListDescription' - meta: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListMetadata' - version: - type: integer - minimum: 1 - _version: - type: string - required: - - id - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts deleted file mode 100644 index 9943a9999a898..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Patch list item API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { ListItemId, ListItemValue, ListItemMetadata } from '../model/list_common.gen'; -import { ListItem } from '../model/list_schemas.gen'; - -export type PatchListItemRequestBody = z.infer; -export const PatchListItemRequestBody = z.object({ - id: ListItemId, - value: ListItemValue.optional(), - meta: ListItemMetadata.optional(), - _version: z.string().optional(), - /** - * Determines when changes made by the request are made visible to search - */ - refresh: z.enum(['true', 'false', 'wait_for']).optional(), -}); -export type PatchListItemRequestBodyInput = z.input; - -export type PatchListItemResponse = z.infer; -export const PatchListItemResponse = ListItem; diff --git a/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml deleted file mode 100644 index f79efc4691dde..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml +++ /dev/null @@ -1,76 +0,0 @@ -openapi: 3.0.0 -info: - title: Patch list item API endpoint - version: '2023-10-31' -paths: - /api/lists/items: - patch: - x-labels: [serverless, ess] - operationId: PatchListItem - x-codegen-enabled: true - summary: Patch a list item - description: Update specific fields of an existing list item using the list item ID. - requestBody: - description: List item's properties - required: true - content: - application/json: - schema: - type: object - properties: - id: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemId' - value: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemValue' - meta: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemMetadata' - _version: - type: string - refresh: - type: string - enum: - - 'true' - - 'false' - - wait_for - description: Determines when changes made by the request are made visible to search - required: - - id - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List item not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts b/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts deleted file mode 100644 index 7bf343d935f2c..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts +++ /dev/null @@ -1,430 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Lists API client for quickstart - * version: Bundle (no version) - */ - -import type { KbnClient } from '@kbn/test'; -import { ToolingLog } from '@kbn/tooling-log'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { catchAxiosErrorFormatAndThrow } from '@kbn/securitysolution-utils'; - -import type { CreateListIndexResponse } from './create_list_index/create_list_index.gen'; -import type { - CreateListItemRequestBodyInput, - CreateListItemResponse, -} from './create_list_item/create_list_item.gen'; -import type { CreateListRequestBodyInput, CreateListResponse } from './create_list/create_list.gen'; -import type { DeleteListIndexResponse } from './delete_list_index/delete_list_index.gen'; -import type { - DeleteListItemRequestQueryInput, - DeleteListItemResponse, -} from './delete_list_item/delete_list_item.gen'; -import type { - DeleteListRequestQueryInput, - DeleteListResponse, -} from './delete_list/delete_list.gen'; -import type { ExportListItemsRequestQueryInput } from './export_list_items/export_list_items.gen'; -import type { - FindListItemsRequestQueryInput, - FindListItemsResponse, -} from './find_list_items/find_list_items.gen'; -import type { FindListsRequestQueryInput, FindListsResponse } from './find_lists/find_lists.gen'; -import type { - ImportListItemsRequestQueryInput, - ImportListItemsResponse, -} from './import_list_items/import_list_items.gen'; -import type { - PatchListItemRequestBodyInput, - PatchListItemResponse, -} from './patch_list_item/patch_list_item.gen'; -import type { PatchListRequestBodyInput, PatchListResponse } from './patch_list/patch_list.gen'; -import type { ReadListIndexResponse } from './read_list_index/read_list_index.gen'; -import type { - ReadListItemRequestQueryInput, - ReadListItemResponse, -} from './read_list_item/read_list_item.gen'; -import type { ReadListPrivilegesResponse } from './read_list_privileges/read_list_privileges.gen'; -import type { ReadListRequestQueryInput, ReadListResponse } from './read_list/read_list.gen'; -import type { - UpdateListItemRequestBodyInput, - UpdateListItemResponse, -} from './update_list_item/update_list_item.gen'; -import type { UpdateListRequestBodyInput, UpdateListResponse } from './update_list/update_list.gen'; - -export interface ClientOptions { - kbnClient: KbnClient; - log: ToolingLog; -} - -export class Client { - readonly kbnClient: KbnClient; - readonly log: ToolingLog; - - constructor(options: ClientOptions) { - this.kbnClient = options.kbnClient; - this.log = options.log; - } - /** - * Create a new list. - */ - async createList(props: CreateListProps) { - this.log.info(`${new Date().toISOString()} Calling API CreateList`); - return this.kbnClient - .request({ - path: '/api/lists', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Create `.lists` and `.items` data streams in the relevant space. - */ - async createListIndex() { - this.log.info(`${new Date().toISOString()} Calling API CreateListIndex`); - return this.kbnClient - .request({ - path: '/api/lists/index', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Create a list item and associate it with the specified list. - -All list items in the same list must be the same type. For example, each list item in an `ip` list must define a specific IP address. -> info -> Before creating a list item, you must create a list. - - */ - async createListItem(props: CreateListItemProps) { - this.log.info(`${new Date().toISOString()} Calling API CreateListItem`); - return this.kbnClient - .request({ - path: '/api/lists/items', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Delete a list using the list ID. -> info -> When you delete a list, all of its list items are also deleted. - - */ - async deleteList(props: DeleteListProps) { - this.log.info(`${new Date().toISOString()} Calling API DeleteList`); - return this.kbnClient - .request({ - path: '/api/lists', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'DELETE', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Delete the `.lists` and `.items` data streams. - */ - async deleteListIndex() { - this.log.info(`${new Date().toISOString()} Calling API DeleteListIndex`); - return this.kbnClient - .request({ - path: '/api/lists/index', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'DELETE', - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Delete a list item using its `id`, or its `list_id` and `value` fields. - */ - async deleteListItem(props: DeleteListItemProps) { - this.log.info(`${new Date().toISOString()} Calling API DeleteListItem`); - return this.kbnClient - .request({ - path: '/api/lists/items', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'DELETE', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Export list item values from the specified list. - */ - async exportListItems(props: ExportListItemsProps) { - this.log.info(`${new Date().toISOString()} Calling API ExportListItems`); - return this.kbnClient - .request({ - path: '/api/lists/items/_export', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Get all list items in the specified list. - */ - async findListItems(props: FindListItemsProps) { - this.log.info(`${new Date().toISOString()} Calling API FindListItems`); - return this.kbnClient - .request({ - path: '/api/lists/items/_find', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Get a paginated subset of lists. By default, the first page is returned, with 20 results per page. - */ - async findLists(props: FindListsProps) { - this.log.info(`${new Date().toISOString()} Calling API FindLists`); - return this.kbnClient - .request({ - path: '/api/lists/_find', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Import list items from a TXT or CSV file. The maximum file size is 9 million bytes. - -You can import items to a new or existing list. - - */ - async importListItems(props: ImportListItemsProps) { - this.log.info(`${new Date().toISOString()} Calling API ImportListItems`); - return this.kbnClient - .request({ - path: '/api/lists/items/_import', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - body: props.attachment, - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Update specific fields of an existing list using the list ID. - */ - async patchList(props: PatchListProps) { - this.log.info(`${new Date().toISOString()} Calling API PatchList`); - return this.kbnClient - .request({ - path: '/api/lists', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'PATCH', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Update specific fields of an existing list item using the list item ID. - */ - async patchListItem(props: PatchListItemProps) { - this.log.info(`${new Date().toISOString()} Calling API PatchListItem`); - return this.kbnClient - .request({ - path: '/api/lists/items', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'PATCH', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Get the details of a list using the list ID. - */ - async readList(props: ReadListProps) { - this.log.info(`${new Date().toISOString()} Calling API ReadList`); - return this.kbnClient - .request({ - path: '/api/lists', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Verify that `.lists` and `.items` data streams exist. - */ - async readListIndex() { - this.log.info(`${new Date().toISOString()} Calling API ReadListIndex`); - return this.kbnClient - .request({ - path: '/api/lists/index', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Get the details of a list item. - */ - async readListItem(props: ReadListItemProps) { - this.log.info(`${new Date().toISOString()} Calling API ReadListItem`); - return this.kbnClient - .request({ - path: '/api/lists/items', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - - query: props.query, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - async readListPrivileges() { - this.log.info(`${new Date().toISOString()} Calling API ReadListPrivileges`); - return this.kbnClient - .request({ - path: '/api/lists/privileges', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'GET', - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Update a list using the list ID. The original list is replaced, and all unspecified fields are deleted. -> info -> You cannot modify the `id` value. - - */ - async updateList(props: UpdateListProps) { - this.log.info(`${new Date().toISOString()} Calling API UpdateList`); - return this.kbnClient - .request({ - path: '/api/lists', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'PUT', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } - /** - * Update a list item using the list item ID. The original list item is replaced, and all unspecified fields are deleted. -> info -> You cannot modify the `id` value. - - */ - async updateListItem(props: UpdateListItemProps) { - this.log.info(`${new Date().toISOString()} Calling API UpdateListItem`); - return this.kbnClient - .request({ - path: '/api/lists/items', - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'PUT', - body: props.body, - }) - .catch(catchAxiosErrorFormatAndThrow); - } -} - -export interface CreateListProps { - body: CreateListRequestBodyInput; -} -export interface CreateListItemProps { - body: CreateListItemRequestBodyInput; -} -export interface DeleteListProps { - query: DeleteListRequestQueryInput; -} -export interface DeleteListItemProps { - query: DeleteListItemRequestQueryInput; -} -export interface ExportListItemsProps { - query: ExportListItemsRequestQueryInput; -} -export interface FindListItemsProps { - query: FindListItemsRequestQueryInput; -} -export interface FindListsProps { - query: FindListsRequestQueryInput; -} -export interface ImportListItemsProps { - query: ImportListItemsRequestQueryInput; - attachment: FormData; -} -export interface PatchListProps { - body: PatchListRequestBodyInput; -} -export interface PatchListItemProps { - body: PatchListItemRequestBodyInput; -} -export interface ReadListProps { - query: ReadListRequestQueryInput; -} -export interface ReadListItemProps { - query: ReadListItemRequestQueryInput; -} -export interface UpdateListProps { - body: UpdateListRequestBodyInput; -} -export interface UpdateListItemProps { - body: UpdateListItemRequestBodyInput; -} diff --git a/packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts deleted file mode 100644 index d744eb15c9b50..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Read list API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { ListId } from '../model/list_common.gen'; -import { List } from '../model/list_schemas.gen'; - -export type ReadListRequestQuery = z.infer; -export const ReadListRequestQuery = z.object({ - /** - * List's `id` value - */ - id: ListId, -}); -export type ReadListRequestQueryInput = z.input; - -export type ReadListResponse = z.infer; -export const ReadListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml deleted file mode 100644 index d932e16f528a5..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml +++ /dev/null @@ -1,58 +0,0 @@ -openapi: 3.0.0 -info: - title: Read list API endpoint - version: '2023-10-31' -paths: - /api/lists: - get: - x-labels: [serverless, ess] - operationId: ReadList - x-codegen-enabled: true - summary: Get list details - description: Get the details of a list using the list ID. - parameters: - - name: id - in: query - required: true - description: List's `id` value - schema: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts b/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts deleted file mode 100644 index 8a5068f72f234..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Read list DS existence status API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -export type ReadListIndexResponse = z.infer; -export const ReadListIndexResponse = z.object({ - list_index: z.boolean(), - list_item_index: z.boolean(), -}); diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml b/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml deleted file mode 100644 index b675264600157..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml +++ /dev/null @@ -1,57 +0,0 @@ -openapi: 3.0.0 -info: - title: Read list DS existence status API endpoint - version: '2023-10-31' -paths: - /api/lists/index: - get: - x-labels: [serverless, ess] - operationId: ReadListIndex - x-codegen-enabled: true - summary: Get status of list data streams - description: Verify that `.lists` and `.items` data streams exist. - responses: - 200: - description: Successful response - content: - application/json: - schema: - type: object - properties: - list_index: - type: boolean - list_item_index: - type: boolean - required: [list_index, list_item_index] - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List data stream(s) not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.ts deleted file mode 100644 index cd0c1d8fca26d..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Read list item API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { ListId } from '../model/list_common.gen'; -import { ListItem } from '../model/list_schemas.gen'; - -export type ReadListItemRequestQuery = z.infer; -export const ReadListItemRequestQuery = z.object({ - /** - * Required if `list_id` and `value` are not specified - */ - id: ListId.optional(), - /** - * Required if `id` is not specified - */ - list_id: ListId.optional(), - /** - * Required if `id` is not specified - */ - value: z.string().optional(), -}); -export type ReadListItemRequestQueryInput = z.input; - -export type ReadListItemResponse = z.infer; -export const ReadListItemResponse = z.union([ListItem, z.array(ListItem)]); diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml deleted file mode 100644 index 4d686f5452e0c..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml +++ /dev/null @@ -1,74 +0,0 @@ -openapi: 3.0.0 -info: - title: Read list item API endpoint - version: '2023-10-31' -paths: - /api/lists/items: - get: - x-labels: [serverless, ess] - operationId: ReadListItem - x-codegen-enabled: true - summary: Get a list item - description: Get the details of a list item. - parameters: - - name: id - in: query - required: false - description: Required if `list_id` and `value` are not specified - schema: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - - name: list_id - in: query - required: false - description: Required if `id` is not specified - schema: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - - name: value - in: query - required: false - description: Required if `id` is not specified - schema: - type: string - responses: - 200: - description: Successful response - content: - application/json: - schema: - oneOf: - - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' - - type: array - items: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List item not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts deleted file mode 100644 index f5eb085fe4aa5..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Update list API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { ListId, ListName, ListDescription, ListMetadata } from '../model/list_common.gen'; -import { List } from '../model/list_schemas.gen'; - -export type UpdateListRequestBody = z.infer; -export const UpdateListRequestBody = z.object({ - id: ListId, - name: ListName, - description: ListDescription, - meta: ListMetadata.optional(), - version: z.number().int().min(1).optional(), - _version: z.string().optional(), -}); -export type UpdateListRequestBodyInput = z.input; - -export type UpdateListResponse = z.infer; -export const UpdateListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml deleted file mode 100644 index c41b52427b63d..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml +++ /dev/null @@ -1,79 +0,0 @@ -openapi: 3.0.0 -info: - title: Update list API endpoint - version: '2023-10-31' -paths: - /api/lists: - put: - x-labels: [serverless, ess] - operationId: UpdateList - x-codegen-enabled: true - summary: Update a list - description: | - Update a list using the list ID. The original list is replaced, and all unspecified fields are deleted. - > info - > You cannot modify the `id` value. - requestBody: - description: List's properties - required: true - content: - application/json: - schema: - type: object - properties: - id: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' - name: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListName' - description: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListDescription' - meta: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListMetadata' - version: - type: integer - minimum: 1 - _version: - type: string - required: - - id - - name - - description - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts deleted file mode 100644 index 052c4c979e844..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Update list item API endpoint - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { ListItemId, ListItemValue, ListItemMetadata } from '../model/list_common.gen'; -import { ListItem } from '../model/list_schemas.gen'; - -export type UpdateListItemRequestBody = z.infer; -export const UpdateListItemRequestBody = z.object({ - id: ListItemId, - value: ListItemValue, - meta: ListItemMetadata.optional(), - _version: z.string().optional(), -}); -export type UpdateListItemRequestBodyInput = z.input; - -export type UpdateListItemResponse = z.infer; -export const UpdateListItemResponse = ListItem; diff --git a/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml deleted file mode 100644 index 6b05e01f35aab..0000000000000 --- a/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml +++ /dev/null @@ -1,73 +0,0 @@ -openapi: 3.0.0 -info: - title: Update list item API endpoint - version: '2023-10-31' -paths: - /api/lists/items: - put: - x-labels: [serverless, ess] - operationId: UpdateListItem - x-codegen-enabled: true - summary: Update a list item - description: | - Update a list item using the list item ID. The original list item is replaced, and all unspecified fields are deleted. - > info - > You cannot modify the `id` value. - requestBody: - description: List item's properties - required: true - content: - application/json: - schema: - type: object - properties: - id: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemId' - value: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemValue' - meta: - $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemMetadata' - _version: - type: string - required: - - id - - value - responses: - 200: - description: Successful response - content: - application/json: - schema: - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' - 400: - description: Invalid input data response - content: - application/json: - schema: - oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 401: - description: Unsuccessful authentication response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 403: - description: Not enough privileges response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - 404: - description: List item not found response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' - 500: - description: Internal server error response - content: - application/json: - schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/package.json b/packages/kbn-securitysolution-lists-common/package.json deleted file mode 100644 index 624c2709ea737..0000000000000 --- a/packages/kbn-securitysolution-lists-common/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "description": "Security Solution Lists common package", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "name": "@kbn/securitysolution-lists-common", - "private": true, - "version": "1.0.0", - "scripts": { - "openapi:generate": "node scripts/openapi_generate", - "openapi:bundle": "node scripts/openapi_bundle" - } -} diff --git a/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js b/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js deleted file mode 100644 index 7a61724759178..0000000000000 --- a/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -require('../../../src/setup_node_env'); -const { join, resolve } = require('path'); -const { bundle } = require('@kbn/openapi-bundler'); - -const ROOT = resolve(__dirname, '..'); - -(async () => { - await bundle({ - sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), - outputFilePath: join( - ROOT, - 'docs/openapi/serverless/security_solution_lists_api_{version}.bundled.schema.yaml' - ), - options: { - includeLabels: ['serverless'], - prototypeDocument: join(ROOT, 'scripts/openapi_bundle_info/lists_serverless.info.yaml'), - }, - }); - - await bundle({ - sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), - outputFilePath: join( - ROOT, - 'docs/openapi/ess/security_solution_lists_api_{version}.bundled.schema.yaml' - ), - options: { - includeLabels: ['ess'], - prototypeDocument: join(ROOT, 'scripts/openapi_bundle_info/lists_ess.info.yaml'), - }, - }); -})(); diff --git a/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js b/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js deleted file mode 100644 index 7adc36ed32cab..0000000000000 --- a/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -require('../../../src/setup_node_env'); -const { join, resolve } = require('path'); -const { generate } = require('@kbn/openapi-generator'); -const { REPO_ROOT } = require('@kbn/repo-info'); - -const ROOT = resolve(__dirname, '..'); - -(async () => { - await generate({ - title: 'OpenAPI Lists API Schemas', - rootDir: ROOT, - sourceGlob: './api/**/*.schema.yaml', - templateName: 'zod_operation_schema', - }); - - await generate({ - title: 'Lists API client for tests', - rootDir: ROOT, - sourceGlob: './api/**/*.schema.yaml', - templateName: 'api_client_supertest', - skipLinting: true, - bundle: { - outFile: join( - REPO_ROOT, - 'x-pack/test/api_integration/services/security_solution_lists_api.gen.ts' - ), - }, - }); - - await generate({ - title: 'Lists API client for quickstart', - rootDir: ROOT, - sourceGlob: './api/**/*.schema.yaml', - templateName: 'api_client_quickstart', - skipLinting: true, - bundle: { - outFile: join( - REPO_ROOT, - 'packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts' - ), - }, - }); -})(); diff --git a/packages/kbn-securitysolution-lists-common/tsconfig.json b/packages/kbn-securitysolution-lists-common/tsconfig.json deleted file mode 100644 index e8149be083552..0000000000000 --- a/packages/kbn-securitysolution-lists-common/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "outDir": "target/types", - "types": ["jest", "node"] - }, - "exclude": ["target/**/*"], - "extends": "../../tsconfig.base.json", - "include": ["**/*.ts"], - "kbn_references": [ - "@kbn/zod-helpers", - "@kbn/openapi-common", - "@kbn/test", - "@kbn/tooling-log", - "@kbn/core-http-common", - "@kbn/securitysolution-utils", - "@kbn/zod", - ] -} diff --git a/packages/kbn-securitysolution-rules/tsconfig.json b/packages/kbn-securitysolution-rules/tsconfig.json deleted file mode 100644 index 9bd4f35cf62a7..0000000000000 --- a/packages/kbn-securitysolution-rules/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-t-grid/index.ts b/packages/kbn-securitysolution-t-grid/index.ts deleted file mode 100644 index fb5ebc443ccda..0000000000000 --- a/packages/kbn-securitysolution-t-grid/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './src/constants'; -export * from './src/utils'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -export * from './src/mock'; diff --git a/packages/kbn-securitysolution-t-grid/package.json b/packages/kbn-securitysolution-t-grid/package.json deleted file mode 100644 index b262a21e7dc62..0000000000000 --- a/packages/kbn-securitysolution-t-grid/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/securitysolution-t-grid", - "version": "1.0.0", - "description": "security solution t-grid packages will allow sharing components between timelines and security_solution plugin until we transfer all functionality to timelines plugin", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-t-grid/src/constants/index.ts b/packages/kbn-securitysolution-t-grid/src/constants/index.ts deleted file mode 100644 index 3ff541240a8c0..0000000000000 --- a/packages/kbn-securitysolution-t-grid/src/constants/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export const HIGHLIGHTED_DROP_TARGET_CLASS_NAME = 'highlighted-drop-target'; -export const EMPTY_PROVIDERS_GROUP_CLASS_NAME = 'empty-providers-group'; - -/** The draggable will move this many pixels via the keyboard when the arrow key is pressed */ -export const KEYBOARD_DRAG_OFFSET = 20; - -export const DRAGGABLE_KEYBOARD_WRAPPER_CLASS_NAME = 'draggable-keyboard-wrapper'; - -export const ROW_RENDERER_CLASS_NAME = 'row-renderer'; - -export const NOTES_CONTAINER_CLASS_NAME = 'notes-container'; - -export const NOTE_CONTENT_CLASS_NAME = 'note-content'; - -/** This class is added to the document body while dragging */ -export const IS_DRAGGING_CLASS_NAME = 'is-dragging'; - -export const HOVER_ACTIONS_ALWAYS_SHOW_CLASS_NAME = 'hover-actions-always-show'; diff --git a/packages/kbn-securitysolution-t-grid/src/mock/index.ts b/packages/kbn-securitysolution-t-grid/src/mock/index.ts deleted file mode 100644 index 51a5726d914f0..0000000000000 --- a/packages/kbn-securitysolution-t-grid/src/mock/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './mock_event_details'; diff --git a/packages/kbn-securitysolution-t-grid/src/utils/api/index.ts b/packages/kbn-securitysolution-t-grid/src/utils/api/index.ts deleted file mode 100644 index 8f7588fdeafd3..0000000000000 --- a/packages/kbn-securitysolution-t-grid/src/utils/api/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { has } from 'lodash/fp'; - -export interface AppError extends Error { - body: { - message: string; - }; -} - -export interface KibanaError extends AppError { - body: { - message: string; - statusCode: number; - }; -} - -export interface SecurityAppError extends AppError { - body: { - message: string; - status_code: number; - }; -} - -export const isKibanaError = (error: unknown): error is KibanaError => - has('message', error) && has('body.message', error) && has('body.statusCode', error); - -export const isSecurityAppError = (error: unknown): error is SecurityAppError => - has('message', error) && has('body.message', error) && has('body.status_code', error); - -export const isAppError = (error: unknown): error is AppError => - isKibanaError(error) || isSecurityAppError(error); - -export const isNotFoundError = (error: unknown) => - (isKibanaError(error) && error.body.statusCode === 404) || - (isSecurityAppError(error) && error.body.status_code === 404); diff --git a/packages/kbn-securitysolution-t-grid/src/utils/drag_and_drop/index.ts b/packages/kbn-securitysolution-t-grid/src/utils/drag_and_drop/index.ts deleted file mode 100644 index 9b7f4bf6ed7dd..0000000000000 --- a/packages/kbn-securitysolution-t-grid/src/utils/drag_and_drop/index.ts +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import type { DropResult } from '@hello-pangea/dnd'; - -export const draggableIdPrefix = 'draggableId'; - -export const droppableIdPrefix = 'droppableId'; - -export const draggableContentPrefix = `${draggableIdPrefix}.content.`; - -export const draggableTimelineProvidersPrefix = `${draggableIdPrefix}.timelineProviders.`; - -export const draggableFieldPrefix = `${draggableIdPrefix}.field.`; - -export const droppableContentPrefix = `${droppableIdPrefix}.content.`; - -export const droppableFieldPrefix = `${droppableIdPrefix}.field.`; - -export const droppableTimelineProvidersPrefix = `${droppableIdPrefix}.timelineProviders.`; - -export const droppableTimelineColumnsPrefix = `${droppableIdPrefix}.timelineColumns.`; - -export const droppableTimelineFlyoutBottomBarPrefix = `${droppableIdPrefix}.flyoutButton.`; - -export const getDraggableId = (dataProviderId: string): string => - `${draggableContentPrefix}${dataProviderId}`; - -export const getDraggableFieldId = ({ - contextId, - fieldId, -}: { - contextId: string; - fieldId: string; -}): string => `${draggableFieldPrefix}${escapeContextId(contextId)}.${escapeFieldId(fieldId)}`; - -export const getTimelineProviderDroppableId = ({ - groupIndex, - timelineId, -}: { - groupIndex: number; - timelineId: string; -}): string => `${droppableTimelineProvidersPrefix}${timelineId}.group.${groupIndex}`; - -export const getTimelineProviderDraggableId = ({ - dataProviderId, - groupIndex, - timelineId, -}: { - dataProviderId: string; - groupIndex: number; - timelineId: string; -}): string => - `${draggableTimelineProvidersPrefix}${timelineId}.group.${groupIndex}.${dataProviderId}`; - -export const getDroppableId = (visualizationPlaceholderId: string): string => - `${droppableContentPrefix}${visualizationPlaceholderId}`; - -export const sourceIsContent = (result: DropResult): boolean => - result.source.droppableId.startsWith(droppableContentPrefix); - -export const sourceAndDestinationAreSameTimelineProviders = (result: DropResult): boolean => { - const regex = /^droppableId\.timelineProviders\.(\S+)\./; - const sourceMatches = result.source.droppableId.match(regex) || []; - const destinationMatches = - (result.destination && result.destination.droppableId.match(regex)) || []; - - return ( - sourceMatches.length >= 2 && - destinationMatches.length >= 2 && - sourceMatches[1] === destinationMatches[1] - ); -}; - -export const draggableIsContent = (result: DropResult | { draggableId: string }): boolean => - result.draggableId.startsWith(draggableContentPrefix); - -export const draggableIsField = (result: DropResult | { draggableId: string }): boolean => - result.draggableId.startsWith(draggableFieldPrefix); - -export const reasonIsDrop = (result: DropResult): boolean => result.reason === 'DROP'; - -export const destinationIsTimelineProviders = (result: DropResult): boolean => - result.destination != null && - result.destination.droppableId.startsWith(droppableTimelineProvidersPrefix); - -export const destinationIsTimelineColumns = (result: DropResult): boolean => - result.destination != null && - result.destination.droppableId.startsWith(droppableTimelineColumnsPrefix); - -export const destinationIsTimelineButton = (result: DropResult): boolean => - result.destination != null && - result.destination.droppableId.startsWith(droppableTimelineFlyoutBottomBarPrefix); - -export const getProviderIdFromDraggable = (result: DropResult): string => - result.draggableId.substring(result.draggableId.lastIndexOf('.') + 1); - -export const getFieldIdFromDraggable = (result: DropResult): string => - unEscapeFieldId(result.draggableId.substring(result.draggableId.lastIndexOf('.') + 1)); - -export const escapeDataProviderId = (path: string) => path.replace(/\./g, '_'); - -export const escapeContextId = (path: string) => path.replace(/\./g, '_'); - -export const escapeFieldId = (path: string) => path.replace(/\./g, '!!!DOT!!!'); - -export const unEscapeFieldId = (path: string) => path.replace(/!!!DOT!!!/g, '.'); - -export const providerWasDroppedOnTimeline = (result: DropResult): boolean => - reasonIsDrop(result) && - draggableIsContent(result) && - sourceIsContent(result) && - destinationIsTimelineProviders(result); - -export const userIsReArrangingProviders = (result: DropResult): boolean => - reasonIsDrop(result) && sourceAndDestinationAreSameTimelineProviders(result); - -export const fieldWasDroppedOnTimelineColumns = (result: DropResult): boolean => - reasonIsDrop(result) && draggableIsField(result) && destinationIsTimelineColumns(result); - -/** - * Prevents fields from being dragged or dropped to any area other than column - * header drop zone in the timeline - */ -export const DRAG_TYPE_FIELD = 'drag-type-field'; - -/** This class is added to the document body while timeline field dragging */ -export const IS_TIMELINE_FIELD_DRAGGING_CLASS_NAME = 'is-timeline-field-dragging'; diff --git a/packages/kbn-securitysolution-t-grid/src/utils/index.ts b/packages/kbn-securitysolution-t-grid/src/utils/index.ts deleted file mode 100644 index c921565845e90..0000000000000 --- a/packages/kbn-securitysolution-t-grid/src/utils/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './api'; -export * from './drag_and_drop'; diff --git a/packages/kbn-securitysolution-t-grid/tsconfig.json b/packages/kbn-securitysolution-t-grid/tsconfig.json deleted file mode 100644 index 9bd4f35cf62a7..0000000000000 --- a/packages/kbn-securitysolution-t-grid/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/kbn-securitysolution-utils/index.ts b/packages/kbn-securitysolution-utils/index.ts deleted file mode 100644 index 8769a281e2201..0000000000000 --- a/packages/kbn-securitysolution-utils/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './src/add_remove_id_to_item'; -export * from './src/axios'; -export * from './src/transform_data_to_ndjson'; -export * from './src/path_validations'; -export * from './src/esql'; -export * from './src/debounce_async/debounce_async'; diff --git a/packages/kbn-securitysolution-utils/jest.config.js b/packages/kbn-securitysolution-utils/jest.config.js deleted file mode 100644 index 43e3bc62c156e..0000000000000 --- a/packages/kbn-securitysolution-utils/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-securitysolution-utils'], -}; diff --git a/packages/kbn-securitysolution-utils/package.json b/packages/kbn-securitysolution-utils/package.json deleted file mode 100644 index 2e18ecbc76425..0000000000000 --- a/packages/kbn-securitysolution-utils/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@kbn/securitysolution-utils", - "version": "1.0.0", - "description": "security solution utilities to use across plugins such lists, security_solution, cases, etc...", - "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", - "private": true, - "sideEffects": false -} \ No newline at end of file diff --git a/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.test.ts b/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.test.ts deleted file mode 100644 index 462f1245500ec..0000000000000 --- a/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { addIdToItem, removeIdFromItem } from '.'; - -jest.mock('uuid', () => ({ - v4: jest.fn().mockReturnValue('123'), -})); - -describe('add_remove_id_to_item', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('addIdToItem', () => { - test('it adds an id to an empty item', () => { - expect(addIdToItem({})).toEqual({ id: '123' }); - }); - - test('it adds a complex object', () => { - expect( - addIdToItem({ - field: '', - type: 'mapping', - value: '', - }) - ).toEqual({ - id: '123', - field: '', - type: 'mapping', - value: '', - }); - }); - - test('it adds an id to an existing item', () => { - expect(addIdToItem({ test: '456' })).toEqual({ id: '123', test: '456' }); - }); - - test('it does not change the id if it already exists', () => { - expect(addIdToItem({ id: '456' })).toEqual({ id: '456' }); - }); - - test('it returns the same reference if it has an id already', () => { - const obj = { id: '456' }; - expect(addIdToItem(obj)).toBe(obj); - }); - - test('it returns a new reference if it adds an id to an item', () => { - const obj = { test: '456' }; - expect(addIdToItem(obj)).not.toBe(obj); - }); - }); - - describe('removeIdFromItem', () => { - test('it removes an id from an item', () => { - expect(removeIdFromItem({ id: '456' })).toEqual({}); - }); - - test('it returns a new reference if it removes an id from an item', () => { - const obj = { id: '123', test: '456' }; - expect(removeIdFromItem(obj)).not.toBe(obj); - }); - - test('it does not effect an item without an id', () => { - expect(removeIdFromItem({ test: '456' })).toEqual({ test: '456' }); - }); - - test('it returns the same reference if it does not have an id already', () => { - const obj = { test: '456' }; - expect(removeIdFromItem(obj)).toBe(obj); - }); - }); -}); diff --git a/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.ts b/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.ts deleted file mode 100644 index b01a0f7db1ec7..0000000000000 --- a/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { v4 as uuidv4 } from 'uuid'; - -/** - * This is useful for when you have arrays without an ID and need to add one for - * ReactJS keys. I break the types slightly by introducing an id to an arbitrary item - * but then cast it back to the regular type T. - * Usage of this could be considered tech debt as I am adding an ID when the backend - * could be doing the same thing but it depends on how you want to model your data and - * if you view modeling your data with id's to please ReactJS a good or bad thing. - * @param item The item to add an id to. - */ -type NotArray = T extends unknown[] ? never : T; -export const addIdToItem = (item: NotArray): T => { - const maybeId = item as typeof item & { id?: string }; - if (maybeId.id != null) { - return item; - } else { - return { ...item, id: uuidv4() }; - } -}; - -/** - * This is to reverse the id you added to your arrays for ReactJS keys. - * @param item The item to remove the id from. - */ -export const removeIdFromItem = ( - item: NotArray -): - | T - | Pick< - T & { - id?: string | undefined; - }, - Exclude - > => { - const maybeId = item as typeof item & { id?: string }; - if (maybeId.id != null) { - const { id, ...noId } = maybeId; - return noId; - } else { - return item; - } -}; diff --git a/packages/kbn-securitysolution-utils/src/axios/index.ts b/packages/kbn-securitysolution-utils/src/axios/index.ts deleted file mode 100644 index c5c0bbe9d1fda..0000000000000 --- a/packages/kbn-securitysolution-utils/src/axios/index.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { AxiosError } from 'axios'; - -export class FormattedAxiosError extends Error { - public readonly request: { - method: string; - url: string; - data: unknown; - }; - public readonly response: { - status: number; - statusText: string; - data: any; - }; - - constructor(axiosError: AxiosError) { - const method = axiosError.config?.method ?? ''; - const url = axiosError.config?.url ?? ''; - - super( - `${axiosError.message}${ - axiosError?.response?.data ? `: ${JSON.stringify(axiosError?.response?.data)}` : '' - }${url ? `\n(Request: ${method} ${url})` : ''}` - ); - - this.request = { - method, - url, - data: axiosError.config?.data ?? '', - }; - - this.response = { - status: axiosError?.response?.status ?? 0, - statusText: axiosError?.response?.statusText ?? '', - data: axiosError?.response?.data, - }; - - this.name = this.constructor.name; - } - - toJSON() { - return { - message: this.message, - request: this.request, - response: this.response, - }; - } - - toString() { - return JSON.stringify(this.toJSON(), null, 2); - } -} - -/** - * Used with `promise.catch()`, it will format the Axios error to a new error and will re-throw - * @param error - */ -export const catchAxiosErrorFormatAndThrow = (error: Error): never => { - if (error instanceof AxiosError) { - throw new FormattedAxiosError(error); - } - - throw error; -}; diff --git a/packages/kbn-securitysolution-utils/src/client_concurrency/index.ts b/packages/kbn-securitysolution-utils/src/client_concurrency/index.ts deleted file mode 100644 index d3a479b441021..0000000000000 --- a/packages/kbn-securitysolution-utils/src/client_concurrency/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import limit from 'p-limit'; - -/** - * This type is just an async function's type - */ -type RequestFactory = () => Promise; - -/** - * Helper function to call a large number of async functions with limited concurrency. - * Example pattern of how to create functions to pass in: - * - * const ruleCopies = duplicateRuleParams(basicRule, 200); - * const functions = ruleCopies.map((rule) => () => detectionsClient.createRule({ body: rule })); - * - * Note that the `map` call in the example returns a *function* that calls detectionsClient.createRule, it doesn't call createRule immediately. - * - * @param functions Async functions to call with limited concurrency - * @param concurrency Maximum number of concurrent function calls - * @returns Results from all functions passed in - */ -export const concurrentlyExec = async ( - requestFactories: Array>, - concurrency: number = 10 -) => { - const limiter = limit(concurrency); - const promises = requestFactories.map((f) => limiter(f)); - return Promise.all(promises); -}; diff --git a/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.ts b/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.ts deleted file mode 100644 index 99fe653b0e21e..0000000000000 --- a/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -/** - * Unlike lodash's debounce, which resolves intermediate calls with the most - * recent value, this implementation waits to resolve intermediate calls until - * the next invocation resolves. - * - * @param fn an async function - * - * @returns A debounced async function that resolves on the next invocation - */ -export function debounceAsync( - fn: (...args: Args) => Result, - intervalMs: number -): (...args: Args) => Promise> { - let timeoutId: ReturnType | undefined; - let resolve: (value: Awaited) => void; - let promise = new Promise>((_resolve) => { - resolve = _resolve; - }); - - return (...args) => { - if (timeoutId) { - clearTimeout(timeoutId); - } - - timeoutId = setTimeout(async () => { - resolve(await fn(...args)); - promise = new Promise((_resolve) => { - resolve = _resolve; - }); - }, intervalMs); - - return promise; - }; -} diff --git a/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts b/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts deleted file mode 100644 index c9b8474b55969..0000000000000 --- a/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { type ESQLAstQueryExpression, parse } from '@kbn/esql-ast'; - -export const isAggregatingQuery = (astExpression: ESQLAstQueryExpression): boolean => - astExpression.commands.some((command) => command.name === 'stats'); - -/** - * compute if esqlQuery is aggregating/grouping, i.e. using STATS...BY command - * @param esqlQuery - * @returns boolean - */ -export const computeIsESQLQueryAggregating = (esqlQuery: string): boolean => { - const { root } = parse(esqlQuery); - return isAggregatingQuery(root); -}; diff --git a/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.ts b/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.ts deleted file mode 100644 index 7cf69b409d5dc..0000000000000 --- a/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; - -/** - * parses ES|QL query and returns array of indices - */ -export const getIndexListFromEsqlQuery = (query: string | undefined): string[] => { - try { - const indexString = getIndexPatternFromESQLQuery(query); - - return getIndexListFromIndexString(indexString); - } catch (e) { - return []; - } -}; - -/** - * transforms sting of indices, separated by commas to array - * index*, index2* => [index*, index2*] - */ -export const getIndexListFromIndexString = (indexString: string | undefined): string[] => { - if (!indexString) { - return []; - } - return indexString.split(',').map((index) => index.trim()); -}; diff --git a/packages/kbn-securitysolution-utils/src/esql/index.ts b/packages/kbn-securitysolution-utils/src/esql/index.ts deleted file mode 100644 index 930ff246988ea..0000000000000 --- a/packages/kbn-securitysolution-utils/src/esql/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export * from './compute_if_esql_query_aggregating'; -export * from './get_index_list_from_esql_query'; -export * from './parse_esql_query'; diff --git a/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts b/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts deleted file mode 100644 index e6dfded200072..0000000000000 --- a/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts +++ /dev/null @@ -1,760 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { - isPathValid, - hasSimpleExecutableName, - OperatingSystem, - ConditionEntryField, - validateWildcardInput, - validateHasWildcardWithWrongOperator, - validatePotentialWildcardInput, - validateFilePathInput, - WILDCARD_WARNING, - FILEPATH_WARNING, -} from '.'; - -describe('validatePotentialWildcardInput', () => { - it('warns on wildcard when field is file.path.text', () => { - expect( - validatePotentialWildcardInput({ - field: 'file.path.text', - os: OperatingSystem.WINDOWS, - value: 'c:\\path*.exe', - }) - ).toEqual(WILDCARD_WARNING); - }); - it('warns on wildcard when field is not file.path.text', () => { - expect( - validatePotentialWildcardInput({ - field: 'event.category', - os: OperatingSystem.WINDOWS, - value: 'some*value', - }) - ).toEqual(WILDCARD_WARNING); - }); -}); - -describe('validateWildcardInput', () => { - it('warns on wildcard for fields that are not file paths', () => { - expect(validateWildcardInput('*')).toEqual(WILDCARD_WARNING); - }); - it('does not warn if no wildcard', () => { - expect(validateWildcardInput('non-wildcard')).toEqual(undefined); - }); -}); - -describe('validateFilePathInput', () => { - describe('windows', () => { - const os = OperatingSystem.WINDOWS; - - it('does not warn on valid filenames', () => { - expect( - validateFilePathInput({ - os, - value: 'C:\\Windows\\*\\FILENAME.EXE-1231205124.gz', - }) - ).not.toBeDefined(); - expect( - validateFilePathInput({ - os, - value: "C:\\Windows\\*\\test$ as2@13---12!@#A,DS.#$^&$!#~ 'as'd.华语.txt", - }) - ).toEqual(undefined); - }); - - it('warns on wildcard in file name at the end of the path', () => { - expect(validateFilePathInput({ os, value: 'c:\\path*.exe' })).toEqual(WILDCARD_WARNING); - expect( - validateFilePathInput({ - os, - value: 'C:\\Windows\\*\\FILENAME.EXE-*.gz', - }) - ).toEqual(WILDCARD_WARNING); - }); - - it('warns on unix paths or non-windows paths', () => { - expect(validateFilePathInput({ os, value: '/opt/bin' })).toEqual(FILEPATH_WARNING); - }); - - it('warns on malformed paths', () => { - expect(validateFilePathInput({ os, value: 'c:\\path/opt' })).toEqual(FILEPATH_WARNING); - expect(validateFilePathInput({ os, value: '1242' })).toEqual(FILEPATH_WARNING); - expect(validateFilePathInput({ os, value: 'w12efdfa' })).toEqual(FILEPATH_WARNING); - expect(validateFilePathInput({ os, value: 'c:\\folder\\' })).toEqual(FILEPATH_WARNING); - }); - }); - describe('unix paths', () => { - const os = - parseInt((Math.random() * 2).toString(), 10) === 1 - ? OperatingSystem.MAC - : OperatingSystem.LINUX; - - it('does not warn on valid filenames', () => { - expect( - validateFilePathInput({ - os, - value: '/opt/*/FILENAME.EXE-1231205124.gz', - }) - ).not.toEqual(WILDCARD_WARNING); - expect( - validateFilePathInput({ - os, - value: "/opt/*/test$ as2@13---12!@#A,DS.#$^&$!#~ 'as'd.华语.txt", - }) - ).not.toEqual(WILDCARD_WARNING); - }); - it('warns on wildcard in file name at the end of the path', () => { - expect(validateFilePathInput({ os, value: '/opt/bin*' })).toEqual(WILDCARD_WARNING); - expect(validateFilePathInput({ os, value: '/opt/FILENAME.EXE-*.gz' })).toEqual( - WILDCARD_WARNING - ); - }); - - it('warns on windows paths', () => { - expect(validateFilePathInput({ os, value: 'd:\\path\\file.exe' })).toEqual(FILEPATH_WARNING); - }); - - it('warns on malformed paths', () => { - expect(validateFilePathInput({ os, value: 'opt/bin\\file.exe' })).toEqual(FILEPATH_WARNING); - expect(validateFilePathInput({ os, value: '1242' })).toEqual(FILEPATH_WARNING); - expect(validateFilePathInput({ os, value: 'w12efdfa' })).toEqual(FILEPATH_WARNING); - expect(validateFilePathInput({ os, value: '/folder/' })).toEqual(FILEPATH_WARNING); - }); - }); -}); - -describe('Wildcard and invalid operator', () => { - it('should return TRUE when operator is not "WILDCARD" and value contains a wildcard', () => { - expect(validateHasWildcardWithWrongOperator({ operator: 'match', value: 'asdf*' })).toEqual( - true - ); - }); - it('should return FALSE when operator is not "WILDCARD" and value does not contain a wildcard', () => { - expect(validateHasWildcardWithWrongOperator({ operator: 'match', value: 'asdf' })).toEqual( - false - ); - }); - it('should return FALSE when operator is "WILDCARD" and value contains a wildcard', () => { - expect(validateHasWildcardWithWrongOperator({ operator: 'wildcard', value: 'asdf*' })).toEqual( - false - ); - }); - it('should return FALSE when operator is "WILDCARD" and value does not contain a wildcard', () => { - expect(validateHasWildcardWithWrongOperator({ operator: 'wildcard', value: 'asdf' })).toEqual( - false - ); - }); -}); - -describe('No Warnings', () => { - it('should not show warnings on non path entries ', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.HASH, - type: 'match', - value: '5d5b09f6dcb2d53a5fffc60c4ac0d55fabdf556069d6631545f42aa6e3500f2e', - }) - ).toEqual(true); - - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.SIGNER, - type: 'match', - value: '', - }) - ).toEqual(true); - }); -}); - -describe('Unacceptable Windows wildcard paths', () => { - it('should not accept paths that do not have a folder name with a wildcard ', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'c:\\folder', - }) - ).toEqual(false); - }); - - it('should not accept paths that do not have a file name with a wildcard ', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'c:\\path.exe', - }) - ).toEqual(false); - }); - - it('should not accept nested paths that do not have a wildcard', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'c:\\folder\\path.exe', - }) - ).toEqual(false); - }); - - it('should not accept paths with * wildcard and /', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'c:/**/path.exe', - }) - ).toEqual(false); - }); - - it('should not accept paths with ? wildcard and /', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'C:/?indows/pat?', - }) - ).toEqual(false); - }); -}); - -describe('Acceptable Windows wildcard paths', () => { - it('should accept wildcards for folders', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'c:\\**\\path.exe', - }) - ).toEqual(true); - }); - - it('should accept wildcards for folders and files', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'e:\\**\\*.exe', - }) - ).toEqual(true); - }); - - it('should accept paths with single wildcard', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'f:\\*', - }) - ).toEqual(true); - - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'f:\\?', - }) - ).toEqual(true); - }); - - it('should accept paths that have wildcard in filenames', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'a:\\*.*', - }) - ).toEqual(true); - }); - - it('should accept paths with ? as wildcard', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'C:\\?indows\\pat?', - }) - ).toEqual(true); - }); - - it('should accept paths with both ? and * as wildcards', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'C:\\*?', - }) - ).toEqual(true); - }); - - it('should accept paths with multiple wildcards', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'C:\\**', - }) - ).toEqual(true); - - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'C:\\??', - }) - ).toEqual(true); - }); -}); - -describe('Acceptable Windows exact paths', () => { - it('should accept paths when it ends with a folder name', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'match', - value: 'c:\\folder', - }) - ).toEqual(true); - }); - - it('should accept paths when it ends with a file name', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'match', - value: 'c:\\path.exe', - }) - ).toEqual(true); - }); - - it('should accept paths when it ends with a filename in a folder', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'match', - value: 'c:\\folder\\path.exe', - }) - ).toEqual(true); - }); -}); - -describe('Acceptable Windows exact paths with hyphens', () => { - it('should accept paths when paths have folder names with hyphens', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'match', - value: 'c:\\hype-folder-name', - }) - ).toEqual(true); - }); - - it('should accept paths when file names have hyphens', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'match', - value: 'c:\\file-name.exe', - }) - ).toEqual(true); - }); -}); - -describe('Unacceptable Windows exact paths', () => { - it('should not accept paths with /', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'match', - value: 'c:/folder/path.exe', - }) - ).toEqual(false); - }); - - it('should not accept paths not having a in the suffix', () => { - expect( - isPathValid({ - os: OperatingSystem.WINDOWS, - field: ConditionEntryField.PATH, - type: 'match', - value: '\\folder\\path.exe', - }) - ).toEqual(false); - }); -}); - -/// -describe('Unacceptable Mac/Linux wildcard paths', () => { - it('should not accept paths that do not have a folder name with a wildcard ', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/folder', - }) - ).toEqual(false); - }); - - it('should not accept paths that do not have a file name with a wildcard ', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/zip.zip', - }) - ).toEqual(false); - }); - - it('should not accept nested paths that do not have a wildcard', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/opt/pack.tar', - }) - ).toEqual(false); - }); - - it('should not accept paths with * wildcard and \\', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'c:\\**\\path.exe', - }) - ).toEqual(false); - }); - - it('should not accept paths with ? wildcard and \\', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: 'C:\\?indows\\pat?', - }) - ).toEqual(false); - }); -}); - -describe('Acceptable Mac/Linux wildcard paths', () => { - it('should accept wildcards for folders', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/**/file.', - }) - ).toEqual(true); - }); - - it('should accept wildcards for folders and files', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/usr/bi?/*.js', - }) - ).toEqual(true); - }); - - it('should accept paths with single wildcard', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/op*', - }) - ).toEqual(true); - - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/op?', - }) - ).toEqual(true); - }); - - it('should accept paths that have wildcard in filenames', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/*.*', - }) - ).toEqual(true); - }); - - it('should accept paths with ? as wildcard', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/usr/?inux/pat?', - }) - ).toEqual(true); - }); - - it('should accept paths with both ? and * as wildcards', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/usr/*?', - }) - ).toEqual(true); - }); - - it('should accept paths with multiple wildcards', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/usr/**', - }) - ).toEqual(true); - - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'wildcard', - value: '/opt/??', - }) - ).toEqual(true); - }); -}); - -describe('Acceptable Mac/Linux exact paths', () => { - it('should accept paths when it is the root path', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'match', - value: '/', - }) - ).toEqual(true); - }); - - it('should accept paths when it ends with a file name', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'match', - value: '/usr/file.ts', - }) - ).toEqual(true); - }); - - it('should accept paths when it ends with a filename in a folder', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'match', - value: '/opt/z.dmg', - }) - ).toEqual(true); - }); -}); - -describe('Acceptable Mac/Linux exact paths with hyphens', () => { - it('should accept paths when paths have folder names with hyphens', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'match', - value: '/hype-folder-name', - }) - ).toEqual(true); - }); - - it('should accept paths when file names have hyphens', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'match', - value: '/file-name.dmg', - }) - ).toEqual(true); - }); -}); - -describe('Unacceptable Mac/Linux exact paths', () => { - it('should not accept paths with \\', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'match', - value: 'c:\\folder\\path.exe', - }) - ).toEqual(false); - }); - - it('should not accept paths not starting with /', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'match', - value: 'opt/bin', - }) - ).toEqual(false); - }); - - it('should not accept paths ending with /', () => { - expect( - isPathValid({ - os: OperatingSystem.MAC, - field: ConditionEntryField.PATH, - type: 'match', - value: '/opt/bin/', - }) - ).toEqual(false); - }); - - it('should not accept file extensions with hyphens', () => { - expect( - isPathValid({ - os: OperatingSystem.LINUX, - field: ConditionEntryField.PATH, - type: 'match', - value: '/opt/bin/file.d-mg', - }) - ).toEqual(false); - }); -}); - -describe('hasSimpleExecutableName', () => { - it('should return TRUE when MAC/LINUX wildcard paths have an executable name', () => { - const os = - parseInt((Math.random() * 2).toString(), 10) === 1 - ? OperatingSystem.MAC - : OperatingSystem.LINUX; - - expect( - hasSimpleExecutableName({ - os, - type: 'wildcard', - value: '/opt/*/app', - }) - ).toEqual(true); - expect( - hasSimpleExecutableName({ - os, - type: 'wildcard', - value: '/op*/**/app.dmg', - }) - ).toEqual(true); - expect( - hasSimpleExecutableName({ - os, - type: 'wildcard', - value: "/sy*/test$ as2@13---12!@#A,DS.#$^&$!#~ 'as'd.华语.txt", - }) - ).toEqual(true); - }); - - it('should return FALSE when MAC/LINUX wildcard paths have a wildcard in executable name', () => { - const os = - parseInt((Math.random() * 2).toString(), 10) === 1 - ? OperatingSystem.MAC - : OperatingSystem.LINUX; - - expect( - hasSimpleExecutableName({ - os, - type: 'wildcard', - value: '/op/*/*pp', - }) - ).toEqual(false); - expect( - hasSimpleExecutableName({ - os, - type: 'wildcard', - value: '/op*/b**/ap.m**', - }) - ).toEqual(false); - }); - - it('should return TRUE when WINDOWS wildcards paths have a executable name', () => { - expect( - hasSimpleExecutableName({ - os: OperatingSystem.WINDOWS, - type: 'wildcard', - value: 'c:\\**\\path.exe', - }) - ).toEqual(true); - expect( - hasSimpleExecutableName({ - os: OperatingSystem.WINDOWS, - type: 'wildcard', - value: 'C:\\*\\file-name.path华语 1234.txt', - }) - ).toEqual(true); - expect( - hasSimpleExecutableName({ - os: OperatingSystem.WINDOWS, - type: 'wildcard', - value: "C:\\*\\test$ as2@13---12!@#A,DS.#$^&$!#~ 'as'd.华语.txt", - }) - ).toEqual(true); - }); - - it('should return FALSE when WINDOWS wildcards paths have a wildcard in executable name', () => { - expect( - hasSimpleExecutableName({ - os: OperatingSystem.WINDOWS, - type: 'wildcard', - value: 'c:\\**\\pa*h.exe', - }) - ).toEqual(false); - }); -}); diff --git a/packages/kbn-securitysolution-utils/src/path_validations/index.ts b/packages/kbn-securitysolution-utils/src/path_validations/index.ts deleted file mode 100644 index 1f1eaf0b01423..0000000000000 --- a/packages/kbn-securitysolution-utils/src/path_validations/index.ts +++ /dev/null @@ -1,245 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { i18n } from '@kbn/i18n'; - -export const WILDCARD_WARNING = i18n.translate('utils.wildcardWarning', { - defaultMessage: `Using wildcards can impact Endpoint performance`, -}); - -export const FILEPATH_WARNING = i18n.translate('utils.filename.pathWarning', { - defaultMessage: `Path may be formed incorrectly; verify value`, -}); - -export enum ConditionEntryField { - HASH = 'process.hash.*', - PATH = 'process.executable.caseless', - SIGNER = 'process.Ext.code_signature', - SIGNER_MAC = 'process.code_signature', -} - -export enum EntryFieldType { - HASH = '.hash.', - EXECUTABLE = '.executable.caseless', - PATH = '.path', - SIGNER = '.code_signature', -} - -export type TrustedAppConditionEntryField = - | 'process.hash.*' - | 'process.executable.caseless' - | 'process.Ext.code_signature' - | 'process.code_signature'; - -export type BlocklistConditionEntryField = - | 'file.hash.*' - | 'file.path' - | 'file.Ext.code_signature' - | 'file.path.caseless'; -export type AllConditionEntryFields = - | TrustedAppConditionEntryField - | BlocklistConditionEntryField - | 'file.path.text'; - -export enum OperatingSystem { - LINUX = 'linux', - MAC = 'macos', - WINDOWS = 'windows', -} - -export type EntryTypes = 'match' | 'wildcard' | 'match_any'; -export type TrustedAppEntryTypes = Extract; -export type EventFiltersTypes = EntryTypes | 'exists' | 'nested'; - -export const validatePotentialWildcardInput = ({ - field = '', - os, - value = '', -}: { - field?: string; - os: OperatingSystem; - value?: string; -}): string | undefined => { - const textInput = value.trim(); - if (field === 'file.path.text') { - return validateFilePathInput({ os, value: textInput }); - } - return validateWildcardInput(textInput); -}; - -export const validateFilePathInput = ({ - os, - value, -}: { - os: OperatingSystem; - value: string; -}): string | undefined => { - const isValidFilePath = isPathValid({ - os, - field: 'file.path.text', - type: 'wildcard', - value, - }); - const hasSimpleFileName = hasSimpleExecutableName({ - os, - type: 'wildcard', - value, - }); - - if (!value.length) { - return FILEPATH_WARNING; - } - - if (isValidFilePath) { - if (hasSimpleFileName !== undefined && !hasSimpleFileName) { - return WILDCARD_WARNING; - } - } else { - return FILEPATH_WARNING; - } -}; - -export const validateWildcardInput = (value: string | string[]): string | undefined => { - const wildcardRegex = /[*?]/; - if (Array.isArray(value)) { - const doesAnyValueContainWildcardInput = value.some((v) => wildcardRegex.test(v)); - if (doesAnyValueContainWildcardInput) { - return WILDCARD_WARNING; - } - } else { - if (wildcardRegex.test(value)) { - return WILDCARD_WARNING; - } - } -}; - -export const validateHasWildcardWithWrongOperator = ({ - operator, - value, -}: { - operator: TrustedAppEntryTypes | EventFiltersTypes; - value: string | string[]; -}): boolean => { - if (operator !== 'wildcard' && validateWildcardInput(value)) { - return true; - } else { - return false; - } -}; - -export const hasSimpleExecutableName = ({ - os, - type, - value, -}: { - os: OperatingSystem; - type: EntryTypes; - value: string; -}): boolean | undefined => { - const separator = os === OperatingSystem.WINDOWS ? '\\' : '/'; - const lastString = value.split(separator).pop(); - if (!lastString) { - return; - } - if (type === 'wildcard') { - return (lastString.split('*').length || lastString.split('?').length) === 1; - } - return true; -}; - -export const isPathValid = ({ - os, - field, - type, - value, -}: { - os: OperatingSystem; - field: AllConditionEntryFields; - type: EntryTypes; - value: string; -}): boolean => { - const pathFields: AllConditionEntryFields[] = [ - 'process.executable.caseless', - 'file.path', - 'file.path.text', - ]; - if (pathFields.includes(field)) { - if (type === 'wildcard') { - return os === OperatingSystem.WINDOWS - ? isWindowsWildcardPathValid(value) - : isLinuxMacWildcardPathValid(value); - } - return doesPathMatchRegex({ value, os }); - } - return true; -}; - -const doesPathMatchRegex = ({ os, value }: { os: OperatingSystem; value: string }): boolean => { - if (os === OperatingSystem.WINDOWS) { - const filePathRegex = - /^[a-z]:(?:|\\\\[^<>:"'/\\|?*]+\\[^<>:"'/\\|?*]+|%\w+%|)[\\](?:[^<>:"'/\\|?*]+[\\/])*([^<>:"'/\\|?*])+$/i; - return filePathRegex.test(value); - } - return /^(\/|(\/[\w\-]+)+|\/[\w\-]+\.[\w]+|(\/[\w-]+)+\/[\w\-]+\.[\w]+)$/i.test(value); -}; - -const isWindowsWildcardPathValid = (path: string): boolean => { - const firstCharacter = path[0]; - const lastCharacter = path.slice(-1); - const trimmedValue = path.trim(); - const hasSlash = /\//.test(trimmedValue); - if (path.length === 0) { - return false; - } else if ( - hasSlash || - trimmedValue.length !== path.length || - firstCharacter === '^' || - lastCharacter === '\\' || - !hasWildcard({ path, isWindowsPath: true }) - ) { - return false; - } else { - return true; - } -}; - -const isLinuxMacWildcardPathValid = (path: string): boolean => { - const firstCharacter = path[0]; - const lastCharacter = path.slice(-1); - const trimmedValue = path.trim(); - if (path.length === 0) { - return false; - } else if ( - trimmedValue.length !== path.length || - firstCharacter !== '/' || - lastCharacter === '/' || - path.length > 1024 === true || - path.includes('//') === true || - !hasWildcard({ path, isWindowsPath: false }) - ) { - return false; - } else { - return true; - } -}; - -const hasWildcard = ({ - path, - isWindowsPath, -}: { - path: string; - isWindowsPath: boolean; -}): boolean => { - for (const pathComponent of path.split(isWindowsPath ? '\\' : '/')) { - if (/[\*|\?]+/.test(pathComponent) === true) { - return true; - } - } - return false; -}; diff --git a/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts b/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts deleted file mode 100644 index 8c4e8289b1dd3..0000000000000 --- a/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { transformDataToNdjson } from '.'; - -export const ANCHOR_DATE = '2020-02-20T03:57:54.037Z'; - -const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE) => ({ - author: [], - id: '7a7065d7-6e8b-4aae-8d20-c93613dec9f9', - created_at: new Date(anchorDate).toISOString(), - updated_at: new Date(anchorDate).toISOString(), - created_by: 'elastic', - description: 'some description', - enabled: true, - false_positives: ['false positive 1', 'false positive 2'], - from: 'now-6m', - immutable: false, - name: 'Query with a rule id', - query: 'user.name: root or user.name: admin', - references: ['test 1', 'test 2'], - severity: 'high', - severity_mapping: [], - updated_by: 'elastic_kibana', - tags: ['some fake tag 1', 'some fake tag 2'], - to: 'now', - type: 'query', - threat: [], - version: 1, - output_index: '.siem-signals-default', - max_signals: 100, - risk_score: 55, - risk_score_mapping: [], - language: 'kuery', - rule_id: 'query-rule-id', - interval: '5m', - exceptions_list: [], -}); - -describe('transformDataToNdjson', () => { - test('if rules are empty it returns an empty string', () => { - const ruleNdjson = transformDataToNdjson([]); - expect(ruleNdjson).toEqual(''); - }); - - test('single rule will transform with new line ending character for ndjson', () => { - const rule = getRulesSchemaMock(); - const ruleNdjson = transformDataToNdjson([rule]); - expect(ruleNdjson.endsWith('\n')).toBe(true); - }); - - test('multiple rules will transform with two new line ending characters for ndjson', () => { - const result1 = getRulesSchemaMock(); - const result2 = getRulesSchemaMock(); - result2.id = 'some other id'; - result2.rule_id = 'some other id'; - result2.name = 'Some other rule'; - - const ruleNdjson = transformDataToNdjson([result1, result2]); - // this is how we count characters in JavaScript :-) - const count = ruleNdjson.split('\n').length - 1; - expect(count).toBe(2); - }); - - test('you can parse two rules back out without errors', () => { - const result1 = getRulesSchemaMock(); - const result2 = getRulesSchemaMock(); - result2.id = 'some other id'; - result2.rule_id = 'some other id'; - result2.name = 'Some other rule'; - - const ruleNdjson = transformDataToNdjson([result1, result2]); - const ruleStrings = ruleNdjson.split('\n'); - const reParsed1 = JSON.parse(ruleStrings[0]); - const reParsed2 = JSON.parse(ruleStrings[1]); - expect(reParsed1).toEqual(result1); - expect(reParsed2).toEqual(result2); - }); -}); diff --git a/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.ts b/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.ts deleted file mode 100644 index b20606c356efe..0000000000000 --- a/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -export const transformDataToNdjson = (data: unknown[]): string => { - if (data.length !== 0) { - const dataString = data.map((item) => JSON.stringify(item)).join('\n'); - return `${dataString}\n`; - } else { - return ''; - } -}; diff --git a/packages/kbn-securitysolution-utils/tsconfig.json b/packages/kbn-securitysolution-utils/tsconfig.json deleted file mode 100644 index d45b0c973af87..0000000000000 --- a/packages/kbn-securitysolution-utils/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/i18n", - "@kbn/esql-utils", - "@kbn/esql-ast", - "@kbn/esql-validation-autocomplete" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts index 41a194f5f1e5d..c6995c6e2d4ca 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts @@ -772,7 +772,9 @@ export const runActionTestSuite = ({ // Reindex doesn't return any errors on its own, so we have to test // together with waitForReindexTask - describe('reindex & waitForReindexTask', () => { + // Flaky: https://github.com/elastic/kibana/issues/166190 + // Reported here: https://github.com/elastic/kibana/issues/167273 + describe.skip('reindex & waitForReindexTask', () => { it('resolves right when reindex succeeds without reindex script', async () => { const res = (await reindex({ client, diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile b/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile index e868cb73cb8db..7d9eaac886964 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile +++ b/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile @@ -114,7 +114,7 @@ EXPOSE 5601 RUN for iter in {1..10}; do \ microdnf update --setopt=tsflags=nodocs -y && \ microdnf install --setopt=tsflags=nodocs -y \ - fontconfig freetype shadow-utils nss findutils && \ + fontconfig liberation-fonts-common freetype shadow-utils nss findutils && \ microdnf clean all && exit_code=0 && break || exit_code=$? && echo "microdnf error: retry $iter in 10s" && \ sleep 10; \ done; \ @@ -126,7 +126,7 @@ RUN for iter in {1..10}; do \ apt-get update && \ apt-get upgrade -y && \ apt-get install -y --no-install-recommends \ - fontconfig libnss3 curl ca-certificates && \ + fontconfig fonts-liberation libnss3 curl ca-certificates && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && exit_code=0 && break || exit_code=$? && echo "apt-get error: retry $iter in 10s" && \ sleep 10; \ @@ -134,7 +134,7 @@ RUN for iter in {1..10}; do \ (exit $exit_code) {{/ubuntu}} {{#wolfi}} -RUN apk --no-cache add bash curl fontconfig libstdc++ libnss findutils shadow ca-certificates +RUN apk --no-cache add bash curl fontconfig font-liberation libstdc++ libnss findutils shadow ca-certificates {{/wolfi}} # Bring in Kibana from the initial stage. diff --git a/src/dev/code_coverage/ingest_coverage/__tests__/enumerate_patterns.test.js b/src/dev/code_coverage/ingest_coverage/__tests__/enumerate_patterns.test.js index 5faeab1acb539..540b51a294983 100644 --- a/src/dev/code_coverage/ingest_coverage/__tests__/enumerate_patterns.test.js +++ b/src/dev/code_coverage/ingest_coverage/__tests__/enumerate_patterns.test.js @@ -17,13 +17,13 @@ const log = new ToolingLog({ }); describe(`enumeratePatterns`, () => { - it(`should resolve x-pack/plugins/screenshotting/server/browsers/extract/unzip.ts to kibana-screenshotting`, () => { + it(`should resolve x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/unzip.ts to kibana-screenshotting`, () => { const actual = enumeratePatterns(REPO_ROOT)(log)( - new Map([['x-pack/plugins/screenshotting', ['kibana-screenshotting']]]) + new Map([['x-pack/platform/plugins/shared/screenshotting', ['kibana-screenshotting']]]) ); expect(actual.flat()).toContain( - 'x-pack/plugins/screenshotting/server/browsers/extract/unzip.ts kibana-screenshotting' + 'x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/unzip.ts kibana-screenshotting' ); }); it(`should resolve src/plugins/charts/common/static/color_maps/color_maps.ts to kibana-app`, () => { diff --git a/src/dev/precommit_hook/casing_check_config.js b/src/dev/precommit_hook/casing_check_config.js index b437c15688b94..30383559e7fe0 100644 --- a/src/dev/precommit_hook/casing_check_config.js +++ b/src/dev/precommit_hook/casing_check_config.js @@ -182,10 +182,10 @@ export const TEMPORARILY_IGNORED_PATHS = [ 'x-pack/plugins/monitoring/public/icons/health-green.svg', 'x-pack/plugins/monitoring/public/icons/health-red.svg', 'x-pack/plugins/monitoring/public/icons/health-yellow.svg', - 'x-pack/plugins/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Medium.ttf', - 'x-pack/plugins/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Regular.ttf', - 'x-pack/plugins/screenshotting/server/assets/fonts/roboto/Roboto-Italic.ttf', - 'x-pack/plugins/screenshotting/server/assets/fonts/roboto/Roboto-Medium.ttf', - 'x-pack/plugins/screenshotting/server/assets/fonts/roboto/Roboto-Regular.ttf', - 'x-pack/plugins/screenshotting/server/assets/img/logo-grey.png', + 'x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Medium.ttf', + 'x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Regular.ttf', + 'x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/Roboto-Italic.ttf', + 'x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/Roboto-Medium.ttf', + 'x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/Roboto-Regular.ttf', + 'x-pack/platform/plugins/shared/screenshotting/server/assets/img/logo-grey.png', ]; diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index cd9359f891845..13ca8de9bdc84 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -49,7 +49,7 @@ export const storybookAliases = { inventory: 'x-pack/plugins/observability_solution/inventory/.storybook', investigate: 'x-pack/solutions/observability/plugins/investigate_app/.storybook', kibana_react: 'src/plugins/kibana_react/.storybook', - lists: 'x-pack/plugins/lists/.storybook', + lists: 'x-pack/solutions/security/plugins/lists/.storybook', logs_explorer: 'x-pack/plugins/observability_solution/logs_explorer/.storybook', management: 'packages/kbn-management/storybook/config', observability: 'x-pack/solutions/observability/plugins/observability/.storybook', diff --git a/packages/kbn-securitysolution-es-utils/README.md b/src/platform/packages/shared/kbn-securitysolution-es-utils/README.md similarity index 100% rename from packages/kbn-securitysolution-es-utils/README.md rename to src/platform/packages/shared/kbn-securitysolution-es-utils/README.md diff --git a/packages/kbn-securitysolution-es-utils/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/index.ts diff --git a/src/platform/packages/shared/kbn-securitysolution-es-utils/jest.config.js b/src/platform/packages/shared/kbn-securitysolution-es-utils/jest.config.js new file mode 100644 index 0000000000000..3a654a3a269ea --- /dev/null +++ b/src/platform/packages/shared/kbn-securitysolution-es-utils/jest.config.js @@ -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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/src/platform/packages/shared/kbn-securitysolution-es-utils'], +}; diff --git a/packages/kbn-securitysolution-es-utils/kibana.jsonc b/src/platform/packages/shared/kbn-securitysolution-es-utils/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-es-utils/kibana.jsonc rename to src/platform/packages/shared/kbn-securitysolution-es-utils/kibana.jsonc diff --git a/packages/kbn-securitysolution-es-utils/package.json b/src/platform/packages/shared/kbn-securitysolution-es-utils/package.json similarity index 100% rename from packages/kbn-securitysolution-es-utils/package.json rename to src/platform/packages/shared/kbn-securitysolution-es-utils/package.json diff --git a/packages/kbn-securitysolution-es-utils/src/bad_request_error/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/bad_request_error/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/bad_request_error/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/bad_request_error/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/create_boostrap_index/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/create_boostrap_index/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/create_boostrap_index/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/create_boostrap_index/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/create_data_stream/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/create_data_stream/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/create_data_stream/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/create_data_stream/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/decode_version/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/decode_version/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/decode_version/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/decode_version/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/delete_all_index/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_all_index/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/delete_all_index/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_all_index/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/delete_data_stream/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_data_stream/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/delete_data_stream/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_data_stream/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/delete_index_template/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_index_template/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/delete_index_template/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_index_template/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/delete_policy/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_policy/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/delete_policy/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_policy/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/delete_template/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_template/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/delete_template/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/delete_template/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/elasticsearch_client/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/elasticsearch_client/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/elasticsearch_client/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/elasticsearch_client/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/encode_hit_version/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/encode_hit_version/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/encode_hit_version/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/encode_hit_version/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/get_bootstrap_index_exists/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_bootstrap_index_exists/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/get_bootstrap_index_exists/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_bootstrap_index_exists/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/get_data_stream_exists/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_data_stream_exists/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/get_data_stream_exists/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_data_stream_exists/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/get_index_aliases/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_index_aliases/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/get_index_aliases/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_index_aliases/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/get_index_count/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_index_count/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/get_index_count/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_index_count/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/get_index_exists/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_index_exists/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/get_index_exists/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_index_exists/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/get_index_template_exists/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_index_template_exists/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/get_index_template_exists/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_index_template_exists/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/get_policy_exists/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_policy_exists/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/get_policy_exists/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_policy_exists/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/get_template_exists/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_template_exists/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/get_template_exists/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/get_template_exists/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/migrate_to_data_stream/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/migrate_to_data_stream/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/migrate_to_data_stream/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/migrate_to_data_stream/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/put_mappings/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/put_mappings/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/put_mappings/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/put_mappings/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/read_index/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/read_index/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/read_index/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/read_index/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/read_privileges/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/read_privileges/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/read_privileges/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/remove_policy_from_index/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/remove_policy_from_index/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/remove_policy_from_index/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/remove_policy_from_index/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/set_index_template/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/set_index_template/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/set_index_template/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/set_index_template/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/set_policy/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/set_policy/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/set_policy/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/set_policy/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/set_template/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/set_template/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/set_template/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/set_template/index.ts diff --git a/packages/kbn-securitysolution-es-utils/src/transform_error/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/transform_error/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/transform_error/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/transform_error/index.test.ts diff --git a/packages/kbn-securitysolution-es-utils/src/transform_error/index.ts b/src/platform/packages/shared/kbn-securitysolution-es-utils/src/transform_error/index.ts similarity index 100% rename from packages/kbn-securitysolution-es-utils/src/transform_error/index.ts rename to src/platform/packages/shared/kbn-securitysolution-es-utils/src/transform_error/index.ts diff --git a/src/platform/packages/shared/kbn-securitysolution-es-utils/tsconfig.json b/src/platform/packages/shared/kbn-securitysolution-es-utils/tsconfig.json new file mode 100644 index 0000000000000..5a16f6bdaff6c --- /dev/null +++ b/src/platform/packages/shared/kbn-securitysolution-es-utils/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "target/**/*", + ], + "kbn_references": [ + "@kbn/zod-helpers", + "@kbn/zod", + ] +} diff --git a/packages/kbn-securitysolution-io-ts-types/README.md b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/README.md similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/README.md rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/README.md diff --git a/packages/kbn-securitysolution-io-ts-types/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/index.ts diff --git a/src/platform/packages/shared/kbn-securitysolution-io-ts-types/jest.config.js b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/jest.config.js new file mode 100644 index 0000000000000..309c3085d7449 --- /dev/null +++ b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/jest.config.js @@ -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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/src/platform/packages/shared/kbn-securitysolution-io-ts-types'], +}; diff --git a/packages/kbn-securitysolution-io-ts-types/kibana.jsonc b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/kibana.jsonc rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/kibana.jsonc diff --git a/packages/kbn-securitysolution-io-ts-types/package.json b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/package.json similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/package.json rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/package.json diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_array/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_array/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_array/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_array/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_array/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_array/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_array/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_array/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_boolean_false/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_boolean_false/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_boolean_false/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_boolean_false/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_boolean_false/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_boolean_false/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_boolean_false/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_boolean_false/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_boolean_true/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_boolean_true/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_boolean_true/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_boolean_true/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_boolean_true/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_boolean_true/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_boolean_true/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_boolean_true/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_csv_array/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_csv_array/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_csv_array/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_csv_array/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_csv_array/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_csv_array/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_csv_array/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_csv_array/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_empty_string/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_empty_string/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_empty_string/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_empty_string/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_empty_string/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_empty_string/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_empty_string/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_empty_string/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_string_array/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_string_array/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_string_array/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_string_array/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_string_array/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_string_array/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_string_array/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_string_array/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_string_boolean_false/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_string_boolean_false/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_string_boolean_false/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_string_boolean_false/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_string_boolean_false/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_string_boolean_false/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_string_boolean_false/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_string_boolean_false/index.ts diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_uuid/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_uuid/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_uuid/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_uuid/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_uuid/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_uuid/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_value/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_value/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_value/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_value/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_value/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_value/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_value/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_value/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_version_number/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_version_number/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_version_number/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_version_number/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/default_version_number/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_version_number/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/default_version_number/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/default_version_number/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/empty_string_array/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/empty_string_array/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/empty_string_array/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/empty_string_array/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/empty_string_array/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/empty_string_array/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/empty_string_array/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/empty_string_array/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/enumeration/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/enumeration/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/enumeration/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/enumeration/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/enumeration/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/enumeration/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/enumeration/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/enumeration/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/import_query_schema/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/import_query_schema/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/import_query_schema/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/import_query_schema/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/import_query_schema/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/import_query_schema/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/import_query_schema/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/import_query_schema/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/iso_date_string/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/iso_date_string/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/iso_date_string/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/iso_date_string/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/iso_date_string/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/iso_date_string/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/iso_date_string/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/iso_date_string/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/limited_size_array/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/limited_size_array/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/limited_size_array/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/limited_size_array/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/limited_size_array/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/limited_size_array/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/limited_size_array/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/limited_size_array/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/non_empty_array/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_array/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/non_empty_array/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_array/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/non_empty_array/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_array/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/non_empty_array/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_array/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/non_empty_or_nullable_string_array/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_or_nullable_string_array/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/non_empty_or_nullable_string_array/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_or_nullable_string_array/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/non_empty_or_nullable_string_array/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_or_nullable_string_array/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/non_empty_or_nullable_string_array/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_or_nullable_string_array/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/non_empty_string/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_string/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/non_empty_string/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_string/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/non_empty_string/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_string/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/non_empty_string/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_string/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/non_empty_string_array/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_string_array/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/non_empty_string_array/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_string_array/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/non_empty_string_array/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_string_array/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/non_empty_string_array/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/non_empty_string_array/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/number_between_zero_and_one_inclusive/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/number_between_zero_and_one_inclusive/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/number_between_zero_and_one_inclusive/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/number_between_zero_and_one_inclusive/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/number_between_zero_and_one_inclusive/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/number_between_zero_and_one_inclusive/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/number_between_zero_and_one_inclusive/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/number_between_zero_and_one_inclusive/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/only_false_allowed/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/only_false_allowed/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/only_false_allowed/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/only_false_allowed/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/only_false_allowed/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/only_false_allowed/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/only_false_allowed/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/only_false_allowed/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/operator/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/operator/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/operator/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/operator/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/positive_integer/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/positive_integer/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/positive_integer/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/positive_integer/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/positive_integer/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/positive_integer/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/positive_integer/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/positive_integer/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/positive_integer_greater_than_zero/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/positive_integer_greater_than_zero/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/positive_integer_greater_than_zero/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/positive_integer_greater_than_zero/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/positive_integer_greater_than_zero/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/positive_integer_greater_than_zero/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/positive_integer_greater_than_zero/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/positive_integer_greater_than_zero/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/string_to_positive_number/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/string_to_positive_number/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/string_to_positive_number/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/string_to_positive_number/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/time_duration/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/time_duration/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/time_duration/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/time_duration/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/time_duration/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/time_duration/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/time_duration/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/time_duration/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/uuid/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/uuid/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/uuid/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/uuid/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/uuid/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/uuid/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/uuid/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/uuid/index.ts diff --git a/packages/kbn-securitysolution-io-ts-types/src/version/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/version/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/version/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-types/src/version/index.ts diff --git a/src/platform/packages/shared/kbn-securitysolution-io-ts-types/tsconfig.json b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/tsconfig.json new file mode 100644 index 0000000000000..6bc8a84da337d --- /dev/null +++ b/src/platform/packages/shared/kbn-securitysolution-io-ts-types/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "kbn_references": [ + "@kbn/securitysolution-io-ts-utils" + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-io-ts-utils/README.md b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/README.md similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/README.md rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/README.md diff --git a/packages/kbn-securitysolution-io-ts-utils/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/index.ts diff --git a/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/jest.config.js b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/jest.config.js new file mode 100644 index 0000000000000..cfa70556f4b89 --- /dev/null +++ b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/jest.config.js @@ -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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/src/platform/packages/shared/kbn-securitysolution-io-ts-utils'], +}; diff --git a/packages/kbn-securitysolution-io-ts-utils/kibana.jsonc b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/kibana.jsonc rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/kibana.jsonc diff --git a/packages/kbn-securitysolution-io-ts-utils/package.json b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/package.json similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/package.json rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/package.json diff --git a/packages/kbn-securitysolution-io-ts-utils/src/exact_check/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/exact_check/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/src/exact_check/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/exact_check/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-utils/src/exact_check/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/exact_check/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/src/exact_check/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/exact_check/index.ts diff --git a/packages/kbn-securitysolution-io-ts-utils/src/format_errors/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/format_errors/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/src/format_errors/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/format_errors/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-utils/src/format_errors/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/format_errors/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/src/format_errors/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/format_errors/index.ts diff --git a/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts diff --git a/packages/kbn-securitysolution-io-ts-utils/src/test_utils/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/test_utils/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/src/test_utils/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/test_utils/index.ts diff --git a/packages/kbn-securitysolution-io-ts-utils/src/validate/index.test.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/validate/index.test.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/src/validate/index.test.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/validate/index.test.ts diff --git a/packages/kbn-securitysolution-io-ts-utils/src/validate/index.ts b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/validate/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-utils/src/validate/index.ts rename to src/platform/packages/shared/kbn-securitysolution-io-ts-utils/src/validate/index.ts diff --git a/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/tsconfig.json b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/tsconfig.json new file mode 100644 index 0000000000000..ca5354ad56e4f --- /dev/null +++ b/src/platform/packages/shared/kbn-securitysolution-io-ts-utils/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "kbn_references": [ + "@kbn/datemath" + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-rules/README.md b/src/platform/packages/shared/kbn-securitysolution-rules/README.md similarity index 100% rename from packages/kbn-securitysolution-rules/README.md rename to src/platform/packages/shared/kbn-securitysolution-rules/README.md diff --git a/packages/kbn-securitysolution-rules/index.ts b/src/platform/packages/shared/kbn-securitysolution-rules/index.ts similarity index 100% rename from packages/kbn-securitysolution-rules/index.ts rename to src/platform/packages/shared/kbn-securitysolution-rules/index.ts diff --git a/packages/kbn-securitysolution-rules/kibana.jsonc b/src/platform/packages/shared/kbn-securitysolution-rules/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-rules/kibana.jsonc rename to src/platform/packages/shared/kbn-securitysolution-rules/kibana.jsonc diff --git a/packages/kbn-securitysolution-rules/package.json b/src/platform/packages/shared/kbn-securitysolution-rules/package.json similarity index 100% rename from packages/kbn-securitysolution-rules/package.json rename to src/platform/packages/shared/kbn-securitysolution-rules/package.json diff --git a/packages/kbn-securitysolution-rules/src/configuration_constants.ts b/src/platform/packages/shared/kbn-securitysolution-rules/src/configuration_constants.ts similarity index 100% rename from packages/kbn-securitysolution-rules/src/configuration_constants.ts rename to src/platform/packages/shared/kbn-securitysolution-rules/src/configuration_constants.ts diff --git a/packages/kbn-securitysolution-rules/src/rule_type_constants.ts b/src/platform/packages/shared/kbn-securitysolution-rules/src/rule_type_constants.ts similarity index 100% rename from packages/kbn-securitysolution-rules/src/rule_type_constants.ts rename to src/platform/packages/shared/kbn-securitysolution-rules/src/rule_type_constants.ts diff --git a/packages/kbn-securitysolution-rules/src/rule_type_mappings.ts b/src/platform/packages/shared/kbn-securitysolution-rules/src/rule_type_mappings.ts similarity index 100% rename from packages/kbn-securitysolution-rules/src/rule_type_mappings.ts rename to src/platform/packages/shared/kbn-securitysolution-rules/src/rule_type_mappings.ts diff --git a/packages/kbn-securitysolution-rules/src/utils.ts b/src/platform/packages/shared/kbn-securitysolution-rules/src/utils.ts similarity index 100% rename from packages/kbn-securitysolution-rules/src/utils.ts rename to src/platform/packages/shared/kbn-securitysolution-rules/src/utils.ts diff --git a/src/platform/packages/shared/kbn-securitysolution-rules/tsconfig.json b/src/platform/packages/shared/kbn-securitysolution-rules/tsconfig.json new file mode 100644 index 0000000000000..131ff3e6bb433 --- /dev/null +++ b/src/platform/packages/shared/kbn-securitysolution-rules/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/src/plugins/share/public/components/tabs/embed/embed_content.test.tsx b/src/plugins/share/public/components/tabs/embed/embed_content.test.tsx index ee9fdf01588df..edbb9ebb47995 100644 --- a/src/plugins/share/public/components/tabs/embed/embed_content.test.tsx +++ b/src/plugins/share/public/components/tabs/embed/embed_content.test.tsx @@ -18,12 +18,7 @@ describe('Share modal embed content tab', () => { beforeEach(() => { component = mountWithIntl( - jest.fn()} - shareableUrl="/home#/" - /> + ); }); diff --git a/src/plugins/share/public/components/tabs/embed/embed_content.tsx b/src/plugins/share/public/components/tabs/embed/embed_content.tsx index 5a9163097c8dc..a3bc6048e64e5 100644 --- a/src/plugins/share/public/components/tabs/embed/embed_content.tsx +++ b/src/plugins/share/public/components/tabs/embed/embed_content.tsx @@ -34,7 +34,6 @@ type EmbedProps = Pick< | 'objectType' | 'isDirty' > & { - setIsNotSaved: () => void; objectConfig?: ShareContextObjectTypeConfig; }; @@ -55,7 +54,6 @@ export const EmbedContent = ({ shareableUrl, objectType, objectConfig = {}, - setIsNotSaved, isDirty, }: EmbedProps) => { const isMounted = useMountedState(); @@ -67,10 +65,6 @@ export const EmbedContent = ({ const [anonymousAccessParameters] = useState(null); const [usePublicUrl] = useState(false); - useEffect(() => { - if (objectType !== 'dashboard') setIsNotSaved(); - }, [url, setIsNotSaved, objectType]); - const makeUrlEmbeddable = useCallback((tempUrl: string): string => { const embedParam = '?embed=true'; const urlHasQueryString = tempUrl.indexOf('?') !== -1; diff --git a/src/plugins/share/public/components/tabs/embed/index.tsx b/src/plugins/share/public/components/tabs/embed/index.tsx index 44d61833268cd..3c74ce3fe0b13 100644 --- a/src/plugins/share/public/components/tabs/embed/index.tsx +++ b/src/plugins/share/public/components/tabs/embed/index.tsx @@ -8,35 +8,13 @@ */ import { i18n } from '@kbn/i18n'; -import React, { useCallback } from 'react'; +import React from 'react'; import { type IModalTabDeclaration } from '@kbn/shared-ux-tabbed-modal'; import { EmbedContent } from './embed_content'; import { useShareTabsContext } from '../../context'; -const EMBED_TAB_ACTIONS = { - SET_EMBED_URL: 'SET_EMBED_URL', - SET_IS_NOT_SAVED: 'SET_IS_NOT_SAVED', -}; - type IEmbedTab = IModalTabDeclaration<{ url: string; isNotSaved: boolean }>; -const embedTabReducer: IEmbedTab['reducer'] = (state = { url: '', isNotSaved: false }, action) => { - switch (action.type) { - case EMBED_TAB_ACTIONS.SET_IS_NOT_SAVED: - return { - ...state, - isNotSaved: action.payload, - }; - case EMBED_TAB_ACTIONS.SET_IS_NOT_SAVED: - return { - ...state, - isNotSaved: action.payload, - }; - default: - return state; - } -}; - const EmbedTabContent: NonNullable = ({ state, dispatch }) => { const { embedUrlParamExtensions, @@ -47,13 +25,6 @@ const EmbedTabContent: NonNullable = ({ state, dispatch }) isDirty, } = useShareTabsContext()!; - const setIsNotSaved = useCallback(() => { - dispatch({ - type: EMBED_TAB_ACTIONS.SET_IS_NOT_SAVED, - payload: objectType === 'dashboard' ? isDirty : false, - }); - }, [dispatch, objectType, isDirty]); - return ( = ({ state, dispatch }) shareableUrl, objectType, objectConfig: objectTypeMeta?.config?.embed, - isNotSaved: state?.isNotSaved, - setIsNotSaved, isDirty, }} /> @@ -75,6 +44,5 @@ export const embedTab: IEmbedTab = { name: i18n.translate('share.contextMenu.embedCodeTab', { defaultMessage: 'Embed', }), - reducer: embedTabReducer, content: EmbedTabContent, }; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/use_flyout_a11y.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/use_flyout_a11y.tsx index 84c47cc4bd063..18cc98fb94b89 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/use_flyout_a11y.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/use_flyout_a11y.tsx @@ -37,7 +37,7 @@ export const useFlyoutA11y = ({ isXlScreen }: { isXlScreen: boolean }) => { a11yProps: { ref: setFlyoutEl, role: isXlScreen ? 'dialog' : undefined, - tabindex: isXlScreen ? 0 : undefined, + tabIndex: isXlScreen ? 0 : undefined, 'aria-describedby': isXlScreen ? descriptionId : undefined, 'data-no-focus-lock': isXlScreen || undefined, }, diff --git a/tsconfig.base.json b/tsconfig.base.json index 08b86c6b0bae4..b1a1cd9273902 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1160,8 +1160,8 @@ "@kbn/lint-packages-cli/*": ["packages/kbn-lint-packages-cli/*"], "@kbn/lint-ts-projects-cli": ["packages/kbn-lint-ts-projects-cli"], "@kbn/lint-ts-projects-cli/*": ["packages/kbn-lint-ts-projects-cli/*"], - "@kbn/lists-plugin": ["x-pack/plugins/lists"], - "@kbn/lists-plugin/*": ["x-pack/plugins/lists/*"], + "@kbn/lists-plugin": ["x-pack/solutions/security/plugins/lists"], + "@kbn/lists-plugin/*": ["x-pack/solutions/security/plugins/lists/*"], "@kbn/llm-tasks-plugin": ["x-pack/platform/plugins/shared/ai_infra/llm_tasks"], "@kbn/llm-tasks-plugin/*": ["x-pack/platform/plugins/shared/ai_infra/llm_tasks/*"], "@kbn/locator-examples-plugin": ["examples/locator_examples"], @@ -1568,8 +1568,8 @@ "@kbn/screenshot-mode-plugin/*": ["src/plugins/screenshot_mode/*"], "@kbn/screenshotting-example-plugin": ["x-pack/examples/screenshotting_example"], "@kbn/screenshotting-example-plugin/*": ["x-pack/examples/screenshotting_example/*"], - "@kbn/screenshotting-plugin": ["x-pack/plugins/screenshotting"], - "@kbn/screenshotting-plugin/*": ["x-pack/plugins/screenshotting/*"], + "@kbn/screenshotting-plugin": ["x-pack/platform/plugins/shared/screenshotting"], + "@kbn/screenshotting-plugin/*": ["x-pack/platform/plugins/shared/screenshotting/*"], "@kbn/screenshotting-server": ["packages/kbn-screenshotting-server"], "@kbn/screenshotting-server/*": ["packages/kbn-screenshotting-server/*"], "@kbn/search-api-keys-components": ["packages/kbn-search-api-keys-components"], @@ -1656,46 +1656,46 @@ "@kbn/security-test-endpoints-plugin/*": ["x-pack/test/security_functional/plugins/test_endpoints/*"], "@kbn/security-ui-components": ["x-pack/packages/security/ui_components"], "@kbn/security-ui-components/*": ["x-pack/packages/security/ui_components/*"], - "@kbn/securitysolution-autocomplete": ["packages/kbn-securitysolution-autocomplete"], - "@kbn/securitysolution-autocomplete/*": ["packages/kbn-securitysolution-autocomplete/*"], + "@kbn/securitysolution-autocomplete": ["x-pack/solutions/security/packages/kbn-securitysolution-autocomplete"], + "@kbn/securitysolution-autocomplete/*": ["x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/*"], "@kbn/securitysolution-data-table": ["x-pack/solutions/security/packages/data_table"], "@kbn/securitysolution-data-table/*": ["x-pack/solutions/security/packages/data_table/*"], "@kbn/securitysolution-ecs": ["src/platform/packages/shared/kbn-securitysolution-ecs"], "@kbn/securitysolution-ecs/*": ["src/platform/packages/shared/kbn-securitysolution-ecs/*"], - "@kbn/securitysolution-endpoint-exceptions-common": ["packages/kbn-securitysolution-endpoint-exceptions-common"], - "@kbn/securitysolution-endpoint-exceptions-common/*": ["packages/kbn-securitysolution-endpoint-exceptions-common/*"], - "@kbn/securitysolution-es-utils": ["packages/kbn-securitysolution-es-utils"], - "@kbn/securitysolution-es-utils/*": ["packages/kbn-securitysolution-es-utils/*"], - "@kbn/securitysolution-exception-list-components": ["packages/kbn-securitysolution-exception-list-components"], - "@kbn/securitysolution-exception-list-components/*": ["packages/kbn-securitysolution-exception-list-components/*"], - "@kbn/securitysolution-exceptions-common": ["packages/kbn-securitysolution-exceptions-common"], - "@kbn/securitysolution-exceptions-common/*": ["packages/kbn-securitysolution-exceptions-common/*"], - "@kbn/securitysolution-hook-utils": ["packages/kbn-securitysolution-hook-utils"], - "@kbn/securitysolution-hook-utils/*": ["packages/kbn-securitysolution-hook-utils/*"], - "@kbn/securitysolution-io-ts-alerting-types": ["packages/kbn-securitysolution-io-ts-alerting-types"], - "@kbn/securitysolution-io-ts-alerting-types/*": ["packages/kbn-securitysolution-io-ts-alerting-types/*"], - "@kbn/securitysolution-io-ts-list-types": ["packages/kbn-securitysolution-io-ts-list-types"], - "@kbn/securitysolution-io-ts-list-types/*": ["packages/kbn-securitysolution-io-ts-list-types/*"], - "@kbn/securitysolution-io-ts-types": ["packages/kbn-securitysolution-io-ts-types"], - "@kbn/securitysolution-io-ts-types/*": ["packages/kbn-securitysolution-io-ts-types/*"], - "@kbn/securitysolution-io-ts-utils": ["packages/kbn-securitysolution-io-ts-utils"], - "@kbn/securitysolution-io-ts-utils/*": ["packages/kbn-securitysolution-io-ts-utils/*"], - "@kbn/securitysolution-list-api": ["packages/kbn-securitysolution-list-api"], - "@kbn/securitysolution-list-api/*": ["packages/kbn-securitysolution-list-api/*"], - "@kbn/securitysolution-list-constants": ["packages/kbn-securitysolution-list-constants"], - "@kbn/securitysolution-list-constants/*": ["packages/kbn-securitysolution-list-constants/*"], - "@kbn/securitysolution-list-hooks": ["packages/kbn-securitysolution-list-hooks"], - "@kbn/securitysolution-list-hooks/*": ["packages/kbn-securitysolution-list-hooks/*"], - "@kbn/securitysolution-list-utils": ["packages/kbn-securitysolution-list-utils"], - "@kbn/securitysolution-list-utils/*": ["packages/kbn-securitysolution-list-utils/*"], - "@kbn/securitysolution-lists-common": ["packages/kbn-securitysolution-lists-common"], - "@kbn/securitysolution-lists-common/*": ["packages/kbn-securitysolution-lists-common/*"], - "@kbn/securitysolution-rules": ["packages/kbn-securitysolution-rules"], - "@kbn/securitysolution-rules/*": ["packages/kbn-securitysolution-rules/*"], - "@kbn/securitysolution-t-grid": ["packages/kbn-securitysolution-t-grid"], - "@kbn/securitysolution-t-grid/*": ["packages/kbn-securitysolution-t-grid/*"], - "@kbn/securitysolution-utils": ["packages/kbn-securitysolution-utils"], - "@kbn/securitysolution-utils/*": ["packages/kbn-securitysolution-utils/*"], + "@kbn/securitysolution-endpoint-exceptions-common": ["x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common"], + "@kbn/securitysolution-endpoint-exceptions-common/*": ["x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/*"], + "@kbn/securitysolution-es-utils": ["src/platform/packages/shared/kbn-securitysolution-es-utils"], + "@kbn/securitysolution-es-utils/*": ["src/platform/packages/shared/kbn-securitysolution-es-utils/*"], + "@kbn/securitysolution-exception-list-components": ["x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components"], + "@kbn/securitysolution-exception-list-components/*": ["x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/*"], + "@kbn/securitysolution-exceptions-common": ["x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common"], + "@kbn/securitysolution-exceptions-common/*": ["x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/*"], + "@kbn/securitysolution-hook-utils": ["x-pack/solutions/security/packages/kbn-securitysolution-hook-utils"], + "@kbn/securitysolution-hook-utils/*": ["x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/*"], + "@kbn/securitysolution-io-ts-alerting-types": ["x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types"], + "@kbn/securitysolution-io-ts-alerting-types/*": ["x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/*"], + "@kbn/securitysolution-io-ts-list-types": ["x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types"], + "@kbn/securitysolution-io-ts-list-types/*": ["x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/*"], + "@kbn/securitysolution-io-ts-types": ["src/platform/packages/shared/kbn-securitysolution-io-ts-types"], + "@kbn/securitysolution-io-ts-types/*": ["src/platform/packages/shared/kbn-securitysolution-io-ts-types/*"], + "@kbn/securitysolution-io-ts-utils": ["src/platform/packages/shared/kbn-securitysolution-io-ts-utils"], + "@kbn/securitysolution-io-ts-utils/*": ["src/platform/packages/shared/kbn-securitysolution-io-ts-utils/*"], + "@kbn/securitysolution-list-api": ["x-pack/solutions/security/packages/kbn-securitysolution-list-api"], + "@kbn/securitysolution-list-api/*": ["x-pack/solutions/security/packages/kbn-securitysolution-list-api/*"], + "@kbn/securitysolution-list-constants": ["x-pack/solutions/security/packages/kbn-securitysolution-list-constants"], + "@kbn/securitysolution-list-constants/*": ["x-pack/solutions/security/packages/kbn-securitysolution-list-constants/*"], + "@kbn/securitysolution-list-hooks": ["x-pack/solutions/security/packages/kbn-securitysolution-list-hooks"], + "@kbn/securitysolution-list-hooks/*": ["x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/*"], + "@kbn/securitysolution-list-utils": ["x-pack/solutions/security/packages/kbn-securitysolution-list-utils"], + "@kbn/securitysolution-list-utils/*": ["x-pack/solutions/security/packages/kbn-securitysolution-list-utils/*"], + "@kbn/securitysolution-lists-common": ["x-pack/solutions/security/packages/kbn-securitysolution-lists-common"], + "@kbn/securitysolution-lists-common/*": ["x-pack/solutions/security/packages/kbn-securitysolution-lists-common/*"], + "@kbn/securitysolution-rules": ["src/platform/packages/shared/kbn-securitysolution-rules"], + "@kbn/securitysolution-rules/*": ["src/platform/packages/shared/kbn-securitysolution-rules/*"], + "@kbn/securitysolution-t-grid": ["x-pack/solutions/security/packages/kbn-securitysolution-t-grid"], + "@kbn/securitysolution-t-grid/*": ["x-pack/solutions/security/packages/kbn-securitysolution-t-grid/*"], + "@kbn/securitysolution-utils": ["x-pack/solutions/security/packages/kbn-securitysolution-utils"], + "@kbn/securitysolution-utils/*": ["x-pack/solutions/security/packages/kbn-securitysolution-utils/*"], "@kbn/server-http-tools": ["packages/kbn-server-http-tools"], "@kbn/server-http-tools/*": ["packages/kbn-server-http-tools/*"], "@kbn/server-route-repository": ["src/platform/packages/shared/kbn-server-route-repository"], diff --git a/versions.json b/versions.json index 126e39ed0bad2..e7ca2b8539bf5 100644 --- a/versions.json +++ b/versions.json @@ -19,7 +19,7 @@ "previousMajor": true }, { - "version": "8.16.2", + "version": "8.16.3", "branch": "8.16", "previousMajor": true }, diff --git a/x-pack/.gitignore b/x-pack/.gitignore index 97efbef318c90..918a6a7d1c388 100644 --- a/x-pack/.gitignore +++ b/x-pack/.gitignore @@ -6,7 +6,7 @@ /test/functional/apps/**/reports/session /test/reporting/configs/failure_debug/ /plugins/reporting/.chromium/ -/plugins/screenshotting/chromium/ +/platform/plugins/shared/screenshotting/chromium/ /plugins/reporting/.phantom/ /.aws-config.json /.env diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 068f591d4bf9e..00c559ae14c55 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -75,7 +75,7 @@ "xpack.licenseApiGuard": "platform/plugins/private/license_api_guard", "xpack.licenseMgmt": "platform/plugins/shared/license_management", "xpack.licensing": "plugins/licensing", - "xpack.lists": "plugins/lists", + "xpack.lists": "solutions/security/plugins/lists", "xpack.logstash": [ "plugins/logstash" ], @@ -128,7 +128,7 @@ "platform/plugins/private/rollup" ], "xpack.runtimeFields": "platform/plugins/private/runtime_fields", - "xpack.screenshotting": "plugins/screenshotting", + "xpack.screenshotting": "platform/plugins/shared/screenshotting", "xpack.searchSharedUI": "packages/search/shared_ui", "xpack.searchHomepage": "plugins/search_homepage", "xpack.searchIndices": "plugins/search_indices", diff --git a/x-pack/platform/packages/shared/kbn-cloud-security-posture/common/schema/graph/v1.ts b/x-pack/platform/packages/shared/kbn-cloud-security-posture/common/schema/graph/v1.ts index 076c685aca5b9..5b1a48cf940b7 100644 --- a/x-pack/platform/packages/shared/kbn-cloud-security-posture/common/schema/graph/v1.ts +++ b/x-pack/platform/packages/shared/kbn-cloud-security-posture/common/schema/graph/v1.ts @@ -12,7 +12,9 @@ export const graphRequestSchema = schema.object({ nodesLimit: schema.maybe(schema.number()), showUnknownTarget: schema.maybe(schema.boolean()), query: schema.object({ - eventIds: schema.arrayOf(schema.string()), + originEventIds: schema.arrayOf( + schema.object({ id: schema.string(), isAlert: schema.boolean() }) + ), // TODO: use zod for range validation instead of config schema start: schema.oneOf([schema.number(), schema.string()]), end: schema.oneOf([schema.number(), schema.string()]), diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index 162b2b57ab647..be36095456713 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -37591,7 +37591,6 @@ "xpack.securitySolution.detectionEngine.body.summary.message": "La règle {ruleName} a généré {signalsCount} alertes", "xpack.securitySolution.detectionEngine.buttonManageRules": "Gérer les règles", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkActionConfirmationCloseButtonLabel": "Fermer", - "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel": "Modifier {customRulesCount, plural, =1 {# règle personnalisée} other {# règles personnalisées}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmationCancelButtonLabel": "Annuler", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.addIndexPatternsComboboxHelpText": "Entrez le modèle des index Elasticsearch que vous souhaitez ajouter. Par défaut, le menu déroulant comprend des modèles d'indexation définis dans les paramètres avancés de la solution Security.", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.addIndexPatternsComboboxLabel": "Ajouter des modèles d'indexation pour les règles sélectionnées", @@ -37625,8 +37624,6 @@ "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setInvestigationFieldsWarningCallout": "Vous êtes sur le point d'écraser des champs en surbrillance personnalisés pour {rulesCount, plural, one {la règle sélectionnée} other {les # règles sélectionnées}}. Pour appliquer et enregistrer les modifications, cliquez sur Enregistrer.", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setTagsWarningCallout": "Vous êtes sur le point d'écraser les balises pour {rulesCount, plural, one {# règle sélectionnée} other {# règles sélectionnées}}. Sélectionnez Enregistrer pour appliquer les modifications.", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.tagsComoboxRequiredErrorMessage": "Au moins une balise est requise.", - "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkExportConfirmation.confirmButtonLabel": "Exporter {customRulesCount, plural, =1 {# règle personnalisée} other {# règles personnalisées}}", - "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkManualRuleRunConfirmation.confirmButtonLabel": "Planifier {customRulesCount, plural, =1 {# règle personnalisée} other {# règles personnalisées}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkDeleteConfirmationTitle": "Confirmer la suppression groupée", "xpack.securitySolution.detectionEngine.components.allRules.deleteConfirmationCancel": "Annuler", "xpack.securitySolution.detectionEngine.components.allRules.deleteConfirmationConfirm": "Supprimer", @@ -38848,7 +38845,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.addRuleActionsTitle": "Ajouter des actions sur les règles", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.addTagsTitle": "Ajouter des balises", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.applyTimelineTemplateTitle": "Appliquer le modèle de chronologie", - "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkActionConfirmationPartlyTitle": "L'action peut être appliquée uniquement à {customRulesCount, plural, =1 {# règle personnalisée} other {# règles personnalisées}}", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkEditConfirmationDeniedTitle": "Impossible de modifier {rulesCount, plural, =1 {# règle} other {# règles}}.", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkEditWarningToastDescription": "{rulesCount, plural, =1 {# règle est} other {# règles sont}} en cours de mise à jour.", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkEditWarningToastNotifyButtonLabel": "M'envoyer une notification à la fin", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index b2bd6e25ec1f5..faeb7636282f0 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -37449,7 +37449,6 @@ "xpack.securitySolution.detectionEngine.body.summary.message": "ルール{ruleName}は{signalsCount}件のアラートを生成しました", "xpack.securitySolution.detectionEngine.buttonManageRules": "ルールの管理", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkActionConfirmationCloseButtonLabel": "閉じる", - "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel": "{customRulesCount, plural, other {# 個のカスタムルール}}を編集", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmationCancelButtonLabel": "キャンセル", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.addIndexPatternsComboboxHelpText": "追加するElasticsearchインデックスのパターンを入力します。デフォルトでは、ドロップダウンには、セキュリティソリューション詳細設定で定義されたインデックスパターンが含まれます。", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.addIndexPatternsComboboxLabel": "選択したルールのインデックスパターンを追加", @@ -37483,8 +37482,6 @@ "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setInvestigationFieldsWarningCallout": "選択した{rulesCount, plural, other {#個のルール}}のカスタムハイライトされたフィールドを上書きしようとしています。変更を適用して、保存するには、[保存]をクリックします。", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setTagsWarningCallout": "{rulesCount, plural, other {# 個の選択したルール}}のタグを上書きしようとしています。[保存]をクリックすると、変更が適用されます。\n", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.tagsComoboxRequiredErrorMessage": "1つ以上のタグが必要です。", - "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkExportConfirmation.confirmButtonLabel": "{customRulesCount, plural, other {# 個のカスタムルール}}をエクスポート", - "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkManualRuleRunConfirmation.confirmButtonLabel": "{customRulesCount, plural, other {# 個のカスタムルール}}をスケジュール", "xpack.securitySolution.detectionEngine.components.allRules.bulkDeleteConfirmationTitle": "一括削除の確認", "xpack.securitySolution.detectionEngine.components.allRules.deleteConfirmationCancel": "キャンセル", "xpack.securitySolution.detectionEngine.components.allRules.deleteConfirmationConfirm": "削除", @@ -38705,7 +38702,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.addRuleActionsTitle": "ルールアクションを追加", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.addTagsTitle": "タグを追加", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.applyTimelineTemplateTitle": "タイムラインテンプレートを適用", - "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkActionConfirmationPartlyTitle": "このアクションは、{customRulesCount, plural, other {#個のカスタムルール}}にのみ適用できます", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkEditConfirmationDeniedTitle": "{rulesCount, plural, other {# 個のルール}}を編集できません", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkEditWarningToastDescription": "{rulesCount, plural, other {#個のルール}}を更新しています。", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkEditWarningToastNotifyButtonLabel": "完了時に通知", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index 479e9acd6a26d..d466cda357f4b 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -36878,7 +36878,6 @@ "xpack.securitySolution.detectionEngine.body.summary.message": "规则 {ruleName} 生成了 {signalsCount} 个告警", "xpack.securitySolution.detectionEngine.buttonManageRules": "管理规则", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkActionConfirmationCloseButtonLabel": "关闭", - "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel": "编辑 {customRulesCount, plural, other {# 个定制规则}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmationCancelButtonLabel": "取消", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.addIndexPatternsComboboxHelpText": "输入要添加的 Elasticsearch 索引的模式。默认情况下,下拉列表将包括 Security Solution 高级设置中定义的索引模式。", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.addIndexPatternsComboboxLabel": "为选定规则添加索引模式", @@ -36912,8 +36911,6 @@ "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setInvestigationFieldsWarningCallout": "您即将覆盖选定的 {rulesCount, plural, other {# 个规则}}的突出显示的定制字段。要应用并保存更改,请单击'保存'。", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setTagsWarningCallout": "您即将覆盖 {rulesCount, plural, other {# 个选定规则}}的标签,按'保存'可应用更改。", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.tagsComoboxRequiredErrorMessage": "至少需要一个标签。", - "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkExportConfirmation.confirmButtonLabel": "导出 {customRulesCount, plural, other {# 个定制规则}}", - "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkManualRuleRunConfirmation.confirmButtonLabel": "计划 {customRulesCount, plural, other {# 个定制规则}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkDeleteConfirmationTitle": "确认批量删除", "xpack.securitySolution.detectionEngine.components.allRules.deleteConfirmationCancel": "取消", "xpack.securitySolution.detectionEngine.components.allRules.deleteConfirmationConfirm": "删除", @@ -38131,7 +38128,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.addRuleActionsTitle": "添加规则操作", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.addTagsTitle": "添加标签", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.applyTimelineTemplateTitle": "应用时间线模板", - "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkActionConfirmationPartlyTitle": "只能对 {customRulesCount, plural, other {# 个定制规则}}应用此操作", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkEditConfirmationDeniedTitle": "无法编辑 {rulesCount, plural, other {# 个规则}}", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkEditWarningToastDescription": "{rulesCount, plural, other {# 个规则}}正在更新。", "xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkEditWarningToastNotifyButtonLabel": "在完成时通知我", diff --git a/x-pack/platform/plugins/shared/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx b/x-pack/platform/plugins/shared/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx index 4d4e244ac25a4..31dec6ab573dc 100644 --- a/x-pack/platform/plugins/shared/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx +++ b/x-pack/platform/plugins/shared/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx @@ -481,7 +481,7 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { ip_location: { category: processorCategories.DATA_ENRICHMENT, FieldsComponent: IpLocation, - docLinkPath: '/geoip-processor.html', + docLinkPath: '/ip-location-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.ipLocation', { defaultMessage: 'IP Location', }), diff --git a/x-pack/platform/plugins/shared/observability_solution/observability_ai_assistant/server/utils/recall/score_suggestions.ts b/x-pack/platform/plugins/shared/observability_solution/observability_ai_assistant/server/utils/recall/score_suggestions.ts index 7d1a19463cceb..b57e5928ce0ba 100644 --- a/x-pack/platform/plugins/shared/observability_solution/observability_ai_assistant/server/utils/recall/score_suggestions.ts +++ b/x-pack/platform/plugins/shared/observability_solution/observability_ai_assistant/server/utils/recall/score_suggestions.ts @@ -102,7 +102,7 @@ export async function scoreSuggestions({ type: 'string', }, }, - required: ['score'], + required: ['scores'], } as const, }; diff --git a/x-pack/platform/plugins/shared/screenshotting/README.md b/x-pack/platform/plugins/shared/screenshotting/README.md new file mode 100644 index 0000000000000..b129bbb5ad9a1 --- /dev/null +++ b/x-pack/platform/plugins/shared/screenshotting/README.md @@ -0,0 +1,156 @@ +# Kibana Screenshotting + +This plugin provides functionality to take screenshots of the Kibana pages. +It uses Chromium and Puppeteer underneath to run the browser in headless mode. + +## Capabilities +- Canvas workpads screenshots. +- Dashboards screenshots. +- Expressions screenshots. +- PDF generation. +- Batch screenshotting. + +## Usage + +### Getting started +After listing the `screenshotting` plugin in your dependencies, the plugin will be intitalized on the setup stage. +The intitalization process downloads (if it is not already present) and verifies the Chromium build. + +The start contract exposes a public API to interact with the plugin. +Apart from the actual screenshotting functionality, it also provides a way for self-diagnostics. + +Here is an example of how you can take a screenshot of a Kibana URL. + +```typescript +import { lastValueFrom } from 'rxjs'; +import type { CoreSetup, Plugin } from 'src/core/server'; +import type { ScreenshottingStart } from 'x-pack/platform/plugins/shared/screenshotting/server'; + + +interface StartDeps { + screenshotting: ScreenshottingStart; +} + +class ExamplePlugin implements Plugin { + setup({ http, getStartServices }: CoreSetup) { + const router = http.createRouter(); + + router.get( + { + path: '/api/capture', + validate: { + query: schema.object({ + id: schema.string(), + }), + }, + }, + async (context, request, response) => { + const [, { screenshotting }] = await getStartServices(); + const { metrics, results } = await lastValueFrom( + screenshotting.getScreenshots({ + request, + urls: [`http://localhost/app/canvas#/workpad/workpad-${request.query.id}`], + }) + ); + + return response.ok({ + body: JSON.stringify({ + metrics, + image: results[0]?.screenshots[0]?.data.toString('base64'), + errors: results[0]?.renderErrors, + } as ScreenshottingExpressionResponse), + }); + } + ); + } + + start() {} +} + +export function plugin() { + return new ExamplePlugin(); +} +``` + +### API +Please use automatically generated API reference or generated TypeDoc comments to find the complete documentation. + +#### `getScreenshots(options): Observable` +Takes screenshots of multiple pages or an expression and returns an observable with the screenshotting results. + +The `options` parameter is an object with parameters of the screenshotting session. +Option | Required | Default | Description +--- | :---: | --- | --- +`browserTimezone` | no | _none_ | The browser timezone that will be emulated in the browser instance. This option should be used to keep timezone on server and client in sync. +`expression` | no | _none_ | An expression to capture screenshot of. Mutually exclusive with the `urls` parameter. +`format` | no | `'png'` | An output format. It can either be PDF or PNG. In case of capturing multiple URLs, all the screenshots will be combined into one document for PDF format. For PNG format, an array of screenshots will be returned. +`headers` | no | _none_ | Custom headers to be sent with each request. The headers will be used for authorization. +`input` | no | `undefined` | The expression input. +`layout` | no | `{}` | Page layout parameters describing characteristics of the capturing screenshot (e.g., dimensions, zoom, etc.). +`request` | no | _none_ | Kibana Request reference to extract headers from. +`timeouts` | no | _none_ | Timeouts for each phase of the screenshot. +`timeouts.openUrl` | no | (kibana.yml setting) | The timeout in milliseconds to allow the Chromium browser to wait for the "Loading…" screen to dismiss and find the initial data for the page. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. +`timeouts.renderComplete` | no | (kibana.yml setting) | The timeout in milliseconds to allow the Chromium browser to wait for all visualizations to fetch and render the data. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. +`timeouts.waitForElements` | no | (kibana.yml setting) | The timeout in milliseconds to allow the Chromium browser to wait for all visualization panels to load on the page. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. +`urls` | no | `[]` | The list or URL to take screenshots of. Every item can either be a string or a tuple containing a URL and a context. The contextual data can be gathered using the screenshot mode plugin. Mutually exclusive with the `expression` parameter. + +#### `diagnose(flags?: string[]): Observable` +Runs browser diagnostics. +The diagnostic implementation launches Chromium and emits the output in the resulting observable. + +There is a way to override some Chromium command line arguments using the `flags` parameter. + +### Configuration +Option | Default | Description +--- | --- | --- +`xpack.screenshotting.networkPolicy.enabled` | `true` | Capturing a screenshot from a Kibana page involves sending out requests for all the linked web assets. For example, a Markdown visualization can show an image from a remote server. +`xpack.screenshotting.networkPolicy.rules` | Allow http, https, ws, wss, and data. | A policy is specified as an array of objects that describe what to allow or deny based on a host or protocol. If a host or protocol is not specified, the rule matches any host or protocol. +`xpack.screenshotting.browser.autoDownload` | Depends on the `dist` parameter. | Flag to automatically download chromium distribution. +`xpack.screenshotting.browser.chromium.disableSandbox` | Defaults to `false` for all operating systems except Debian and Red Hat Linux, which use `true`. | It is recommended that you research the feasibility of enabling unprivileged user namespaces. An exception is if you are running Kibana in Docker because the container runs in a user namespace with the built-in seccomp/bpf filters. For more information, refer to [Chromium sandbox](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/linux/sandboxing.md). +`xpack.screenshotting.browser.chromium.proxy.enabled` | `false` | Enables the proxy for Chromium to use. +`xpack.screenshotting.browser.chromium.proxy.server` | _none_ | The uri for the proxy server. Providing the username and password for the proxy server via the uri is not supported. +`xpack.screenshotting.browser.chromium.proxy.bypass` | `[]` | An array of hosts that should not go through the proxy server and should use a direct connection instead. Examples of valid entries are "elastic.co", "*.elastic.co", ".elastic.co", ".elastic.co:5601". + +## How It Works +```mermaid +sequenceDiagram + participant User + participant Screenshotting + participant Browser + + User ->> Screenshotting: API call + Screenshotting ->> Browser: Launch browser + activate Browser + Screenshotting ->> Browser: Create page + Screenshotting ->> Browser: Set parameters + Note over Screenshotting,Browser: timezone + + Screenshotting ->> Browser: Open URL + Screenshotting ->> Browser: Set contextual data + Note over Screenshotting,Browser: custom context, screenshot mode flag + Browser ->> Screenshotting: Rendering + + Screenshotting ->> Browser: Wait for visualizations + Note over Screenshotting,Browser: poll for a number of DOM nodes to match
the number of dashboard elements + Screenshotting ->> Browser: Wait for render completion + Note over Screenshotting,Browser: poll for selectors indicating rendering completion + Browser ->> Screenshotting: Page is ready + + Screenshotting ->> Browser: Take screenshot + Browser ->> Screenshotting: Return PNG buffer + Screenshotting ->> User: Return screenshot +``` + +## Testing +### Integration +There is an example plugin that demonstrates integration with the screenshotting plugin. That plugin utilizes expression capturing. + +### Chromium Downloads +To download all Chromium browsers for all platforms and architectures: + +```bash +cd x-pack +npx gulp downloadChromium +``` + +This command is used to provision CI workspaces so that Chromium does not need to be downloaded for every CI run. diff --git a/x-pack/plugins/screenshotting/common/errors.ts b/x-pack/platform/plugins/shared/screenshotting/common/errors.ts similarity index 100% rename from x-pack/plugins/screenshotting/common/errors.ts rename to x-pack/platform/plugins/shared/screenshotting/common/errors.ts diff --git a/x-pack/plugins/screenshotting/common/expression.ts b/x-pack/platform/plugins/shared/screenshotting/common/expression.ts similarity index 100% rename from x-pack/plugins/screenshotting/common/expression.ts rename to x-pack/platform/plugins/shared/screenshotting/common/expression.ts diff --git a/x-pack/plugins/screenshotting/common/index.ts b/x-pack/platform/plugins/shared/screenshotting/common/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/common/index.ts rename to x-pack/platform/plugins/shared/screenshotting/common/index.ts diff --git a/x-pack/plugins/screenshotting/common/layout.ts b/x-pack/platform/plugins/shared/screenshotting/common/layout.ts similarity index 100% rename from x-pack/plugins/screenshotting/common/layout.ts rename to x-pack/platform/plugins/shared/screenshotting/common/layout.ts diff --git a/x-pack/plugins/screenshotting/common/types.ts b/x-pack/platform/plugins/shared/screenshotting/common/types.ts similarity index 100% rename from x-pack/plugins/screenshotting/common/types.ts rename to x-pack/platform/plugins/shared/screenshotting/common/types.ts diff --git a/x-pack/platform/plugins/shared/screenshotting/jest.config.js b/x-pack/platform/plugins/shared/screenshotting/jest.config.js new file mode 100644 index 0000000000000..0fd6d74a1d655 --- /dev/null +++ b/x-pack/platform/plugins/shared/screenshotting/jest.config.js @@ -0,0 +1,16 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/platform/plugins/shared/screenshotting'], + coverageDirectory: + '/target/kibana-coverage/jest/x-pack/platform/plugins/shared/screenshotting', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/x-pack/platform/plugins/shared/screenshotting/server/**/*.{ts}'], +}; diff --git a/x-pack/plugins/screenshotting/jest.integration.config.js b/x-pack/platform/plugins/shared/screenshotting/jest.integration.config.js similarity index 76% rename from x-pack/plugins/screenshotting/jest.integration.config.js rename to x-pack/platform/plugins/shared/screenshotting/jest.integration.config.js index 45a65c93c6af3..d0694061ed92b 100644 --- a/x-pack/plugins/screenshotting/jest.integration.config.js +++ b/x-pack/platform/plugins/shared/screenshotting/jest.integration.config.js @@ -7,6 +7,6 @@ module.exports = { preset: '@kbn/test/jest_integration', - rootDir: '../../..', - roots: ['/x-pack/plugins/screenshotting'], + rootDir: '../../../../..', + roots: ['/x-pack/platform/plugins/shared/screenshotting'], }; diff --git a/x-pack/plugins/screenshotting/kibana.jsonc b/x-pack/platform/plugins/shared/screenshotting/kibana.jsonc similarity index 100% rename from x-pack/plugins/screenshotting/kibana.jsonc rename to x-pack/platform/plugins/shared/screenshotting/kibana.jsonc diff --git a/x-pack/plugins/screenshotting/public/app/app.scss b/x-pack/platform/plugins/shared/screenshotting/public/app/app.scss similarity index 100% rename from x-pack/plugins/screenshotting/public/app/app.scss rename to x-pack/platform/plugins/shared/screenshotting/public/app/app.scss diff --git a/x-pack/plugins/screenshotting/public/app/app.tsx b/x-pack/platform/plugins/shared/screenshotting/public/app/app.tsx similarity index 100% rename from x-pack/plugins/screenshotting/public/app/app.tsx rename to x-pack/platform/plugins/shared/screenshotting/public/app/app.tsx diff --git a/x-pack/plugins/screenshotting/public/app/index.ts b/x-pack/platform/plugins/shared/screenshotting/public/app/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/public/app/index.ts rename to x-pack/platform/plugins/shared/screenshotting/public/app/index.ts diff --git a/x-pack/plugins/screenshotting/public/app/screenshot_mode_context.ts b/x-pack/platform/plugins/shared/screenshotting/public/app/screenshot_mode_context.ts similarity index 100% rename from x-pack/plugins/screenshotting/public/app/screenshot_mode_context.ts rename to x-pack/platform/plugins/shared/screenshotting/public/app/screenshot_mode_context.ts diff --git a/x-pack/plugins/screenshotting/public/index.ts b/x-pack/platform/plugins/shared/screenshotting/public/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/public/index.ts rename to x-pack/platform/plugins/shared/screenshotting/public/index.ts diff --git a/x-pack/plugins/screenshotting/public/plugin.tsx b/x-pack/platform/plugins/shared/screenshotting/public/plugin.tsx similarity index 100% rename from x-pack/plugins/screenshotting/public/plugin.tsx rename to x-pack/platform/plugins/shared/screenshotting/public/plugin.tsx diff --git a/x-pack/plugins/screenshotting/server/__mocks__/puppeteer.ts b/x-pack/platform/plugins/shared/screenshotting/server/__mocks__/puppeteer.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/__mocks__/puppeteer.ts rename to x-pack/platform/plugins/shared/screenshotting/server/__mocks__/puppeteer.ts diff --git a/x-pack/plugins/screenshotting/server/assets/fonts/noto/LICENSE_OFL.txt b/x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/LICENSE_OFL.txt similarity index 100% rename from x-pack/plugins/screenshotting/server/assets/fonts/noto/LICENSE_OFL.txt rename to x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/LICENSE_OFL.txt diff --git a/x-pack/plugins/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Medium.ttf b/x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Medium.ttf similarity index 100% rename from x-pack/plugins/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Medium.ttf rename to x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Medium.ttf diff --git a/x-pack/plugins/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Regular.ttf b/x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Regular.ttf similarity index 100% rename from x-pack/plugins/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Regular.ttf rename to x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/NotoSansCJKtc-Regular.ttf diff --git a/x-pack/plugins/screenshotting/server/assets/fonts/noto/index.js b/x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/index.js similarity index 100% rename from x-pack/plugins/screenshotting/server/assets/fonts/noto/index.js rename to x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/noto/index.js diff --git a/x-pack/plugins/screenshotting/server/assets/fonts/roboto/LICENSE.txt b/x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/LICENSE.txt similarity index 100% rename from x-pack/plugins/screenshotting/server/assets/fonts/roboto/LICENSE.txt rename to x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/LICENSE.txt diff --git a/x-pack/plugins/screenshotting/server/assets/fonts/roboto/Roboto-Italic.ttf b/x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/Roboto-Italic.ttf similarity index 100% rename from x-pack/plugins/screenshotting/server/assets/fonts/roboto/Roboto-Italic.ttf rename to x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/Roboto-Italic.ttf diff --git a/x-pack/plugins/screenshotting/server/assets/fonts/roboto/Roboto-Medium.ttf b/x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/Roboto-Medium.ttf similarity index 100% rename from x-pack/plugins/screenshotting/server/assets/fonts/roboto/Roboto-Medium.ttf rename to x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/Roboto-Medium.ttf diff --git a/x-pack/plugins/screenshotting/server/assets/fonts/roboto/Roboto-Regular.ttf b/x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/Roboto-Regular.ttf similarity index 100% rename from x-pack/plugins/screenshotting/server/assets/fonts/roboto/Roboto-Regular.ttf rename to x-pack/platform/plugins/shared/screenshotting/server/assets/fonts/roboto/Roboto-Regular.ttf diff --git a/x-pack/plugins/screenshotting/server/assets/img/logo-grey.png b/x-pack/platform/plugins/shared/screenshotting/server/assets/img/logo-grey.png similarity index 100% rename from x-pack/plugins/screenshotting/server/assets/img/logo-grey.png rename to x-pack/platform/plugins/shared/screenshotting/server/assets/img/logo-grey.png diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/driver.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/driver.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/driver.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/driver.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver_factory/index.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver_factory/index.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver_factory/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver_factory/index.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/metrics.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver_factory/metrics.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/metrics.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver_factory/metrics.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/metrics.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver_factory/metrics.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/metrics.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver_factory/metrics.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/index.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/integration_tests/downloads.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/integration_tests/downloads.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/integration_tests/downloads.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/integration_tests/downloads.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/strip_unsafe_headers.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/strip_unsafe_headers.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/strip_unsafe_headers.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/strip_unsafe_headers.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/strip_unsafe_headers.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/strip_unsafe_headers.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/strip_unsafe_headers.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/strip_unsafe_headers.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/templates/footer.handlebars.html b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/templates/footer.handlebars.html similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/templates/footer.handlebars.html rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/templates/footer.handlebars.html diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/templates/header.handlebars.html b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/templates/header.handlebars.html similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/templates/header.handlebars.html rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/templates/header.handlebars.html diff --git a/x-pack/plugins/screenshotting/server/browsers/chromium/templates/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/templates/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/chromium/templates/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/templates/index.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/download/checksum.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/download/checksum.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/download/checksum.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/download/checksum.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/download/checksum.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/download/checksum.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/download/checksum.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/download/checksum.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/download/fetch.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/download/fetch.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/download/fetch.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/download/fetch.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/download/fetch.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/download/fetch.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/download/fetch.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/download/fetch.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/download/index.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/download/index.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/download/index.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/download/index.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/download/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/download/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/download/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/download/index.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/extract/__fixtures__/file.md b/x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/__fixtures__/file.md similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/extract/__fixtures__/file.md rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/__fixtures__/file.md diff --git a/x-pack/plugins/screenshotting/server/browsers/extract/__fixtures__/file.md.zip b/x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/__fixtures__/file.md.zip similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/extract/__fixtures__/file.md.zip rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/__fixtures__/file.md.zip diff --git a/x-pack/plugins/screenshotting/server/browsers/extract/extract.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/extract.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/extract/extract.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/extract.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/extract/extract.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/extract.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/extract/extract.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/extract.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/extract/extract_error.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/extract_error.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/extract/extract_error.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/extract_error.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/extract/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/extract/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/index.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/extract/unzip.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/unzip.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/extract/unzip.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/unzip.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/extract/unzip.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/unzip.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/extract/unzip.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/extract/unzip.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/index.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/install.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/install.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/install.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/install.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/mock.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/mock.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/mock.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/mock.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/network_policy.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/network_policy.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/network_policy.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/network_policy.test.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/network_policy.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/network_policy.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/network_policy.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/network_policy.ts diff --git a/x-pack/plugins/screenshotting/server/browsers/safe_child_process.ts b/x-pack/platform/plugins/shared/screenshotting/server/browsers/safe_child_process.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/browsers/safe_child_process.ts rename to x-pack/platform/plugins/shared/screenshotting/server/browsers/safe_child_process.ts diff --git a/x-pack/plugins/screenshotting/server/cloud/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/cloud/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/cloud/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/cloud/index.ts diff --git a/x-pack/plugins/screenshotting/server/config/schema.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/config/schema.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/config/schema.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/config/schema.test.ts diff --git a/x-pack/plugins/screenshotting/server/constants.ts b/x-pack/platform/plugins/shared/screenshotting/server/constants.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/constants.ts rename to x-pack/platform/plugins/shared/screenshotting/server/constants.ts diff --git a/x-pack/plugins/screenshotting/server/formats/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/index.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/index.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/README.md b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/README.md similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/README.md rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/README.md diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/constants.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/constants.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/constants.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/constants.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/get_doc_options.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/get_doc_options.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/get_doc_options.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/get_doc_options.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/get_font.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/get_font.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/get_font.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/get_font.test.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/get_font.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/get_font.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/get_font.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/get_font.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/get_template.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/get_template.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/get_template.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/get_template.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/index.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/integration_tests/buggy_worker.js b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/integration_tests/buggy_worker.js similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/integration_tests/buggy_worker.js rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/integration_tests/buggy_worker.js diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/integration_tests/memory_leak_worker.js b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/integration_tests/memory_leak_worker.js similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/integration_tests/memory_leak_worker.js rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/integration_tests/memory_leak_worker.js diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/integration_tests/pdfmaker.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/integration_tests/pdfmaker.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/integration_tests/pdfmaker.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/integration_tests/pdfmaker.test.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/pdfmaker.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/pdfmaker.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/pdfmaker.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/pdfmaker.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/types.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/types.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/types.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/types.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/worker.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/worker.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/worker.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/worker.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/worker_dependencies.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/worker_dependencies.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/worker_dependencies.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/worker_dependencies.ts diff --git a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/worker_src_harness.js b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/worker_src_harness.js similarity index 90% rename from x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/worker_src_harness.js rename to x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/worker_src_harness.js index ca319ace9d027..05a6c8eaa9759 100644 --- a/x-pack/plugins/screenshotting/server/formats/pdf/pdf_maker/worker_src_harness.js +++ b/x-pack/platform/plugins/shared/screenshotting/server/formats/pdf/pdf_maker/worker_src_harness.js @@ -11,6 +11,6 @@ */ // eslint-disable-next-line @kbn/imports/no_boundary_crossing -require('../../../../../../../src/setup_node_env'); +require('../../../../../../../../../src/setup_node_env'); // eslint-disable-next-line @kbn/imports/uniform_imports require('./worker.ts'); diff --git a/x-pack/plugins/screenshotting/server/formats/png.ts b/x-pack/platform/plugins/shared/screenshotting/server/formats/png.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/formats/png.ts rename to x-pack/platform/plugins/shared/screenshotting/server/formats/png.ts diff --git a/x-pack/plugins/screenshotting/server/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/index.ts diff --git a/x-pack/plugins/screenshotting/server/layouts/base_layout.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/base_layout.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/base_layout.ts rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/base_layout.ts diff --git a/x-pack/plugins/screenshotting/server/layouts/canvas_layout.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/canvas_layout.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/canvas_layout.ts rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/canvas_layout.ts diff --git a/x-pack/plugins/screenshotting/server/layouts/create_layout.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/create_layout.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/create_layout.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/create_layout.test.ts diff --git a/x-pack/plugins/screenshotting/server/layouts/create_layout.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/create_layout.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/create_layout.ts rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/create_layout.ts diff --git a/x-pack/plugins/screenshotting/server/layouts/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/index.ts diff --git a/x-pack/plugins/screenshotting/server/layouts/mock.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/mock.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/mock.ts rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/mock.ts diff --git a/x-pack/plugins/screenshotting/server/layouts/preserve_layout.css b/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.css similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/preserve_layout.css rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.css diff --git a/x-pack/plugins/screenshotting/server/layouts/preserve_layout.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/preserve_layout.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.test.ts diff --git a/x-pack/plugins/screenshotting/server/layouts/preserve_layout.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/preserve_layout.ts rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.ts diff --git a/x-pack/plugins/screenshotting/server/layouts/print_layout.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/print_layout.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/layouts/print_layout.ts rename to x-pack/platform/plugins/shared/screenshotting/server/layouts/print_layout.ts diff --git a/x-pack/plugins/screenshotting/server/mock.ts b/x-pack/platform/plugins/shared/screenshotting/server/mock.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/mock.ts rename to x-pack/platform/plugins/shared/screenshotting/server/mock.ts diff --git a/x-pack/plugins/screenshotting/server/plugin.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/plugin.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/plugin.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/plugin.test.ts diff --git a/x-pack/plugins/screenshotting/server/plugin.ts b/x-pack/platform/plugins/shared/screenshotting/server/plugin.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/plugin.ts rename to x-pack/platform/plugins/shared/screenshotting/server/plugin.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/__snapshots__/index.test.ts.snap b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/__snapshots__/index.test.ts.snap similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/__snapshots__/index.test.ts.snap rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/__snapshots__/index.test.ts.snap diff --git a/x-pack/plugins/screenshotting/server/screenshots/constants.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/constants.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/constants.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/constants.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/event_logger/index.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/event_logger/index.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/event_logger/index.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/event_logger/index.test.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/event_logger/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/event_logger/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/event_logger/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/event_logger/index.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_element_position_data.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_element_position_data.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_element_position_data.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_element_position_data.test.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_element_position_data.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_element_position_data.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_element_position_data.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_element_position_data.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_number_of_items.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_number_of_items.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_number_of_items.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_number_of_items.test.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_number_of_items.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_number_of_items.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_number_of_items.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_number_of_items.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_pdf.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_pdf.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_pdf.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_pdf.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_render_errors.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_render_errors.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_render_errors.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_render_errors.test.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_render_errors.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_render_errors.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_render_errors.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_render_errors.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_screenshots.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_screenshots.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_screenshots.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_screenshots.test.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_screenshots.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_screenshots.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_screenshots.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_screenshots.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_time_range.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_time_range.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_time_range.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_time_range.test.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/get_time_range.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_time_range.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/get_time_range.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/get_time_range.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/index.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/index.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/index.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/index.test.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/index.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/index.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/index.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/index.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/inject_css.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/inject_css.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/inject_css.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/inject_css.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/mock.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/mock.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/mock.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/mock.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/observable.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/observable.test.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/observable.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/observable.test.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/observable.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/observable.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/observable.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/observable.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/open_url.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/open_url.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/open_url.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/open_url.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/screenshots.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/screenshots.test.ts similarity index 98% rename from x-pack/plugins/screenshotting/server/screenshots/screenshots.test.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/screenshots.test.ts index 4f217ef96c611..95261626e15fa 100644 --- a/x-pack/plugins/screenshotting/server/screenshots/screenshots.test.ts +++ b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/screenshots.test.ts @@ -30,7 +30,8 @@ describe('class Screenshots', () => { let mockLogger: Logger; let mockScreenshotModeSetup: ScreenshotModePluginSetup; - const mockBinaryPath = '/kibana/x-pack/plugins/screenshotting/chromium/linux/headless_shell'; + const mockBinaryPath = + '/kibana/x-pack/platform/plugins/shared/screenshotting/chromium/linux/headless_shell'; const mockBasePath = '/kibanaTest1'; beforeEach(() => { diff --git a/x-pack/plugins/screenshotting/server/screenshots/screenshots.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/screenshots.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/screenshots.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/screenshots.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/types.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/types.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/types.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/types.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/wait_for_render.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/wait_for_render.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/wait_for_render.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/wait_for_render.ts diff --git a/x-pack/plugins/screenshotting/server/screenshots/wait_for_visualizations.ts b/x-pack/platform/plugins/shared/screenshotting/server/screenshots/wait_for_visualizations.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/screenshots/wait_for_visualizations.ts rename to x-pack/platform/plugins/shared/screenshotting/server/screenshots/wait_for_visualizations.ts diff --git a/x-pack/plugins/screenshotting/server/utils.ts b/x-pack/platform/plugins/shared/screenshotting/server/utils.ts similarity index 100% rename from x-pack/plugins/screenshotting/server/utils.ts rename to x-pack/platform/plugins/shared/screenshotting/server/utils.ts diff --git a/x-pack/platform/plugins/shared/screenshotting/tsconfig.json b/x-pack/platform/plugins/shared/screenshotting/tsconfig.json new file mode 100644 index 0000000000000..200c6d9c2592e --- /dev/null +++ b/x-pack/platform/plugins/shared/screenshotting/tsconfig.json @@ -0,0 +1,33 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + "../../../../../typings/**/*" + ], + "kbn_references": [ + "@kbn/core", + { "path": "../../../../../src/setup_node_env/tsconfig.json" }, + "@kbn/expressions-plugin", + "@kbn/screenshot-mode-plugin", + "@kbn/cloud-plugin", + "@kbn/utility-types", + "@kbn/logging", + "@kbn/std", + "@kbn/i18n", + "@kbn/utils", + "@kbn/core-logging-server-mocks", + "@kbn/logging-mocks", + "@kbn/core-http-server", + "@kbn/core-plugins-server", + "@kbn/task-manager-plugin", + "@kbn/screenshotting-server", + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts index d73610892098d..ff73095ac2427 100644 --- a/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts +++ b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts @@ -295,4 +295,7 @@ export const getGenAiTokenTracking = async ({ }; export const shouldTrackGenAiToken = (actionTypeId: string) => - actionTypeId === '.gen-ai' || actionTypeId === '.bedrock' || actionTypeId === '.gemini'; + actionTypeId === '.gen-ai' || + actionTypeId === '.bedrock' || + actionTypeId === '.gemini' || + actionTypeId === '.inference'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/authentication_panel/authentication_panel_actions.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/authentication_panel/authentication_panel_actions.tsx index ba6e9d2c19316..49d15c041f145 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/authentication_panel/authentication_panel_actions.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/authentication_panel/authentication_panel_actions.tsx @@ -61,7 +61,7 @@ export const AuthenticationPanelActions: React.FC = () => { ) : currentAuth === null ? ( enableEditing(currentAuth)} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/domains_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/domains_panel.tsx index 41af7db78b6be..60f2e52211972 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/domains_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/domains_panel.tsx @@ -47,7 +47,7 @@ export const DomainsPanel: React.FC = () => { data-telemetry-id="entSearchContent-crawler-domainManagement-addDomain-addDomain" onClick={openFlyout} size="s" - color="success" + color="primary" iconType="plusInCircle" > {i18n.translate('xpack.enterpriseSearch.crawler.addDomainFlyout.openButtonLabel', { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_ml_inference_button.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_ml_inference_button.tsx index 1f8bc30e2903c..c7c296a443ebf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_ml_inference_button.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_ml_inference_button.tsx @@ -79,7 +79,7 @@ const AddButton: React.FC<{ + - + - +

{i18n.translate( 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.title', @@ -87,7 +87,7 @@ export const DeployModel = ({ > { hasIndexIngestionPipeline ? ( - + {i18n.translate( 'xpack.enterpriseSearch.content.indices.pipelines.ingestionPipeline.customBadge', { defaultMessage: 'Custom' } diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/search_labs_banner/search_labs_banner.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/search_labs_banner/search_labs_banner.tsx index d9f1be314a56e..a1b3302cd35a8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/search_labs_banner/search_labs_banner.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/search_labs_banner/search_labs_banner.tsx @@ -36,10 +36,11 @@ export const SearchLabsBanner: React.FC = () => { ({ iconType="plusInCircle" disabled={isEditing} onClick={editNewItem} - color="success" + color="primary" data-test-subj="inlineEditableTableActionButton" > {addButtonText || diff --git a/x-pack/plugins/enterprise_search/public/applications/vector_search/components/dev_tools_console_code_block/dev_tools_console_code_block.tsx b/x-pack/plugins/enterprise_search/public/applications/vector_search/components/dev_tools_console_code_block/dev_tools_console_code_block.tsx index d48011d54cdff..46a60456be7cc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/vector_search/components/dev_tools_console_code_block/dev_tools_console_code_block.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/vector_search/components/dev_tools_console_code_block/dev_tools_console_code_block.tsx @@ -39,7 +39,7 @@ export const DevToolsConsoleCodeBlock: React.FC = return ( - + { return css` - color: ${euiTheme.colors.text}; + color: ${euiTheme.colors.textParagraph}; `; }, [euiTheme]); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx index dd3945664bd6f..a0329a1c9ce0a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_select_hosts.test.tsx @@ -42,7 +42,8 @@ jest.mock('../../../../../hooks', () => { }; }); -describe('StepSelectHosts', () => { +// FLAKY: https://github.com/elastic/kibana/issues/203307 +describe.skip('StepSelectHosts', () => { const packageInfo: PackageInfo = { name: 'apache', version: '1.0.0', diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/devtools_request.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/devtools_request.tsx index 91ca089f2ffe3..81f2304efee99 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/devtools_request.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/devtools_request.tsx @@ -11,7 +11,6 @@ import { i18n } from '@kbn/i18n'; import { omit } from 'lodash'; import { set } from '@kbn/safer-lodash-set'; -import { ExperimentalFeaturesService } from '../../../../../services'; import { generateCreatePackagePolicyDevToolsRequest, generateCreateAgentPolicyDevToolsRequest, @@ -39,12 +38,7 @@ export function useDevToolsRequest({ packageInfo?: PackageInfo; packagePolicyId?: string; }) { - const { showDevtoolsRequest: isShowDevtoolRequestExperimentEnabled } = - ExperimentalFeaturesService.get(); - - const showDevtoolsRequest = - !HIDDEN_API_REFERENCE_PACKAGES.includes(packageInfo?.name ?? '') && - isShowDevtoolRequestExperimentEnabled; + const showDevtoolsRequest = !HIDDEN_API_REFERENCE_PACKAGES.includes(packageInfo?.name ?? ''); const [devtoolRequest, devtoolRequestDescription] = useMemo(() => { if (selectedPolicyTab === SelectedPolicyTab.NEW) { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx index 50baac84ff4a0..efb7066b0d5e0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx @@ -40,7 +40,6 @@ import { ConfirmDeployAgentPolicyModal, } from '../../../components'; import { DevtoolsRequestFlyoutButton } from '../../../../../components'; -import { ExperimentalFeaturesService } from '../../../../../services'; import { generateUpdateAgentPolicyDevToolsRequest } from '../../../services'; import { UNKNOWN_SPACE } from '../../../../../../../../common/constants'; @@ -155,7 +154,6 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( setIsLoading(false); }; - const { showDevtoolsRequest } = ExperimentalFeaturesService.get(); const devtoolRequest = useMemo( () => generateUpdateAgentPolicyDevToolsRequest( @@ -235,28 +233,26 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( /> - {showDevtoolsRequest ? ( - - 0 || - hasAdvancedSettingsErrors || - hasInvalidSpaceError + + 0 || + hasAdvancedSettingsErrors || + hasInvalidSpaceError + } + btnProps={{ + color: 'text', + }} + description={i18n.translate( + 'xpack.fleet.editAgentPolicy.devtoolsRequestDescription', + { + defaultMessage: 'This Kibana request updates an agent policy.', } - btnProps={{ - color: 'text', - }} - description={i18n.translate( - 'xpack.fleet.editAgentPolicy.devtoolsRequestDescription', - { - defaultMessage: 'This Kibana request updates an agent policy.', - } - )} - request={devtoolRequest} - /> - - ) : null} + )} + request={devtoolRequest} + /> + = ({ /> ); - const { showDevtoolsRequest } = ExperimentalFeaturesService.get(); const agentPolicyContent = useMemo( () => generateCreateAgentPolicyDevToolsRequest(agentPolicy, withSysMonitoring), [agentPolicy, withSysMonitoring] @@ -128,25 +126,23 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ - {showDevtoolsRequest ? ( - - 0 || - hasAdvancedSettingsErrors || - hasInvalidSpaceError + + 0 || + hasAdvancedSettingsErrors || + hasInvalidSpaceError + } + description={i18n.translate( + 'xpack.fleet.createAgentPolicy.devtoolsRequestDescription', + { + defaultMessage: 'This Kibana request creates a new agent policy.', } - description={i18n.translate( - 'xpack.fleet.createAgentPolicy.devtoolsRequestDescription', - { - defaultMessage: 'This Kibana request creates a new agent policy.', - } - )} - request={agentPolicyContent} - /> - - ) : null} + )} + request={agentPolicyContent} + /> + { return css` - color: ${euiTheme.colors.text}; + color: ${euiTheme.colors.textParagraph}; `; }, [euiTheme]); const isReadOnly = useIsReadOnly(); diff --git a/x-pack/plugins/fleet/public/components/danger_eui_context_menu_item.tsx b/x-pack/plugins/fleet/public/components/danger_eui_context_menu_item.tsx index 87fb523121cfe..b7983ac255fb6 100644 --- a/x-pack/plugins/fleet/public/components/danger_eui_context_menu_item.tsx +++ b/x-pack/plugins/fleet/public/components/danger_eui_context_menu_item.tsx @@ -5,9 +5,19 @@ * 2.0. */ -import styled from 'styled-components'; -import { EuiContextMenuItem } from '@elastic/eui'; +import React from 'react'; +import { css } from '@emotion/react'; +import type { EuiContextMenuItemProps } from '@elastic/eui'; +import { EuiContextMenuItem, useEuiTheme } from '@elastic/eui'; -export const DangerEuiContextMenuItem = styled(EuiContextMenuItem)` - color: ${(props) => props.theme.eui.euiColorDangerText}; -`; +export const DangerEuiContextMenuItem = (props: EuiContextMenuItemProps) => { + const theme = useEuiTheme(); + return ( + + ); +}; diff --git a/x-pack/plugins/fleet/server/constants/fleet_es_assets.ts b/x-pack/plugins/fleet/server/constants/fleet_es_assets.ts index 621adc5b3b81c..384a77afd112e 100644 --- a/x-pack/plugins/fleet/server/constants/fleet_es_assets.ts +++ b/x-pack/plugins/fleet/server/constants/fleet_es_assets.ts @@ -11,7 +11,7 @@ import { getESAssetMetadata } from '../services/epm/elasticsearch/meta'; const meta = getESAssetMetadata(); -export const FLEET_INSTALL_FORMAT_VERSION = '1.3.0'; +export const FLEET_INSTALL_FORMAT_VERSION = '1.4.0'; export const FLEET_AGENT_POLICIES_SCHEMA_VERSION = '1.1.1'; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_system_object.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_system_object.test.ts index 8d80c236aefb0..c4ae211c58fc5 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_system_object.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_save_system_object.test.ts @@ -13,14 +13,12 @@ import { } from '@kbn/core/server/mocks'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common/constants'; +import { FLEET_INSTALL_FORMAT_VERSION } from '../../../../../constants'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../../common/constants'; - import { appContextService } from '../../../../app_context'; import { createAppContextStartContractMock } from '../../../../../mocks'; - import { auditLoggingService } from '../../../../audit_logging'; import { packagePolicyService } from '../../../../package_policy'; - import { createArchiveIteratorFromMap } from '../../../archive/archive_iterator'; import { stepSaveSystemObject } from './step_save_system_object'; @@ -94,7 +92,7 @@ describe('updateLatestExecutedState', () => { 'epm-packages', 'test-integration', { - install_format_schema_version: '1.3.0', + install_format_schema_version: FLEET_INSTALL_FORMAT_VERSION, install_status: 'installed', install_version: '1.0.0', latest_install_failed_attempts: [], @@ -161,7 +159,7 @@ describe('updateLatestExecutedState', () => { 'epm-packages', 'test-integration', { - install_format_schema_version: '1.3.0', + install_format_schema_version: FLEET_INSTALL_FORMAT_VERSION, install_status: 'installed', install_version: '1.0.0', latest_install_failed_attempts: [], diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/semantic_text_banner.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/semantic_text_banner.tsx index b07886c4526f5..2ebcde354bab3 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/semantic_text_banner.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/semantic_text_banner.tsx @@ -57,10 +57,10 @@ export function SemanticTextBanner({ return isSemanticTextBannerDisplayable && isSemanticTextEnabled ? ( <> - + - + {isPlatinumLicense ? platinumLicenseMessage : defaultLicenseMessage} diff --git a/x-pack/plugins/lens/public/app_plugin/share_action.ts b/x-pack/plugins/lens/public/app_plugin/share_action.ts index dbb5d9d61eda9..e9e0c73cd5d67 100644 --- a/x-pack/plugins/lens/public/app_plugin/share_action.ts +++ b/x-pack/plugins/lens/public/app_plugin/share_action.ts @@ -31,7 +31,7 @@ interface ShareableConfiguration export const DEFAULT_LENS_LAYOUT_DIMENSIONS = { width: 1793, // this is a magic number from the reporting tool implementation - // see: x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.ts#L146 + // see: x-pack/platform/plugins/shared/screenshotting/server/browsers/chromium/driver_factory/index.ts#L146 height: 1086, }; diff --git a/x-pack/plugins/lists/README.md b/x-pack/plugins/lists/README.md deleted file mode 100644 index 02be757303417..0000000000000 --- a/x-pack/plugins/lists/README.md +++ /dev/null @@ -1,238 +0,0 @@ -README.md for developers working on the backend lists on how to get started -using the CURL scripts in the scripts folder. - -The scripts rely on CURL and jq: - -- [CURL](https://curl.haxx.se) -- [jq](https://stedolan.github.io/jq/) - -Install curl and jq (mac instructions) - -```sh -brew update -brew install curl -brew install jq -``` - -Open `$HOME/.zshrc` or `${HOME}.bashrc` depending on your SHELL output from `echo $SHELL` -and add these environment variables: - -```sh -export ELASTICSEARCH_USERNAME=${user} -export ELASTICSEARCH_PASSWORD=${password} -export ELASTICSEARCH_URL=https://${ip}:9200 -export KIBANA_URL=http://localhost:5601 -export TASK_MANAGER_INDEX=.kibana-task-manager-${your user id} -export KIBANA_INDEX=.kibana-${your user id} -``` - -source `$HOME/.zshrc` or `${HOME}.bashrc` to ensure variables are set: - -```sh -source ~/.zshrc -``` - -Open your `kibana.dev.yml` file and add these lines with your name: - -```sh -xpack.lists.listIndex: '.lists-your-name' -xpack.lists.listItemIndex: '.items-your-name' -``` - -Restart Kibana and ensure that you are using `--no-base-path` as changing the base path is a feature but will -get in the way of the CURL scripts written as is. - -Go to the scripts folder `cd kibana/x-pack/plugins/lists/server/scripts` and run: - -```sh -./hard_reset.sh -./post_list.sh -``` - -which will: - -- Delete any existing lists you have -- Delete any existing list items you have -- Delete any existing exception lists you have -- Delete any existing exception list items you have -- Delete any existing mapping, policies, and templates, you might have previously had. -- Add the latest list and list item index and its mappings using your settings from `kibana.dev.yml` environment variable of `xpack.lists.listIndex` and `xpack.lists.listItemIndex`. -- Posts the sample list from `./lists/new/ip_list.json` - -Now you can run - -```sh -./post_list.sh -``` - -You should see the new list created like so: - -```sh -{ - "id": "ip_list", - "created_at": "2020-05-28T19:15:22.344Z", - "created_by": "yo", - "description": "This list describes bad internet ip", - "name": "Simple list with an ip", - "tie_breaker_id": "c57efbc4-4977-4a32-995f-cfd296bed521", - "type": "ip", - "updated_at": "2020-05-28T19:15:22.344Z", - "updated_by": "yo" -} -``` - -You can add a list item like so: - -```sh - ./post_list_item.sh -``` - -You should see the new list item created and attached to the above list like so: - -```sh -{ - "id": "hand_inserted_item_id", - "type": "ip", - "value": "127.0.0.1", - "created_at": "2020-05-28T19:15:49.790Z", - "created_by": "yo", - "list_id": "ip_list", - "tie_breaker_id": "a881bf2e-1e17-4592-bba8-d567cb07d234", - "updated_at": "2020-05-28T19:15:49.790Z", - "updated_by": "yo" -} -``` - -If you want to post an exception list it would be like so: - -```sh -./post_exception_list.sh -``` - -You should see the new exception list created like so: - -```sh -{ - "created_at": "2020-05-28T19:16:31.052Z", - "created_by": "yo", - "description": "This is a sample endpoint type exception", - "id": "bcb94680-a117-11ea-ad9d-c71f4820e65b", - "list_id": "endpoint_list", - "name": "Sample Endpoint Exception List", - "namespace_type": "single", - "tags": [ - "user added string for a tag", - "malware" - ], - "tie_breaker_id": "86e08c8c-c970-4b08-a6e2-cdba7bb4e023", - "type": "endpoint", - "updated_at": "2020-05-28T19:16:31.080Z", - "updated_by": "yo" -} -``` - -And you can attach exception list items like so: - -```ts -{ - "comments": [], - "created_at": "2020-05-28T19:17:21.099Z", - "created_by": "yo", - "description": "This is a sample endpoint type exception", - "entries": [ - { - "field": "actingProcess.file.signer", - "operator": "included", - "type": "match", - "value": "Elastic, N.V." - }, - { - "field": "event.category", - "operator": "included", - "type": "match_any", - "value": [ - "process", - "malware" - ] - } - ], - "id": "da8d3b30-a117-11ea-ad9d-c71f4820e65b", - "item_id": "endpoint_list_item", - "list_id": "endpoint_list", - "name": "Sample Endpoint Exception List", - "namespace_type": "single", - "os_types": ["linux"], - "tags": [ - "user added string for a tag", - "malware" - ], - "tie_breaker_id": "21f84703-9476-4af8-a212-aad31e18dcb9", - "type": "simple", - "updated_at": "2020-05-28T19:17:21.123Z", - "updated_by": "yo" -} -``` - -You can then do find for each one like so: - -```sh -./find_lists.sh -``` - -```sh -{ - "cursor": "WzIwLFsiYzU3ZWZiYzQtNDk3Ny00YTMyLTk5NWYtY2ZkMjk2YmVkNTIxIl1d", - "data": [ - { - "id": "ip_list", - "created_at": "2020-05-28T19:15:22.344Z", - "created_by": "yo", - "description": "This list describes bad internet ip", - "name": "Simple list with an ip", - "tie_breaker_id": "c57efbc4-4977-4a32-995f-cfd296bed521", - "type": "ip", - "updated_at": "2020-05-28T19:15:22.344Z", - "updated_by": "yo" - } - ], - "page": 1, - "per_page": 20, - "total": 1 -} -``` - -or for finding exception lists: - -```sh -./find_exception_lists.sh -``` - -```sh -{ - "data": [ - { - "created_at": "2020-05-28T19:16:31.052Z", - "created_by": "yo", - "description": "This is a sample endpoint type exception", - "id": "bcb94680-a117-11ea-ad9d-c71f4820e65b", - "list_id": "endpoint_list", - "name": "Sample Endpoint Exception List", - "namespace_type": "single", - "os_types": ["linux"], - "tags": [ - "user added string for a tag", - "malware" - ], - "tie_breaker_id": "86e08c8c-c970-4b08-a6e2-cdba7bb4e023", - "type": "endpoint", - "updated_at": "2020-05-28T19:16:31.080Z", - "updated_by": "yo" - } - ], - "page": 1, - "per_page": 20, - "total": 1 -} -``` - -See the full scripts folder for all the capabilities. diff --git a/x-pack/plugins/lists/jest.config.js b/x-pack/plugins/lists/jest.config.js deleted file mode 100644 index cb9832920183f..0000000000000 --- a/x-pack/plugins/lists/jest.config.js +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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. - */ - -module.exports = { - collectCoverageFrom: ['/x-pack/plugins/lists/{common,public,server}/**/*.{ts,tsx}'], - coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/lists', - coverageReporters: ['text', 'html'], - preset: '@kbn/test', - rootDir: '../../..', - roots: ['/x-pack/plugins/lists'], -}; diff --git a/x-pack/plugins/lists/tsconfig.json b/x-pack/plugins/lists/tsconfig.json deleted file mode 100644 index 61229d39bdbdd..0000000000000 --- a/x-pack/plugins/lists/tsconfig.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types" - }, - "include": [ - "common/**/*", - "public/**/*", - "server/**/*", - // have to declare *.json explicitly due to https://github.com/microsoft/TypeScript/issues/25636 - "server/**/*.json" - ], - "kbn_references": [ - "@kbn/core", - "@kbn/spaces-plugin", - "@kbn/security-plugin", - "@kbn/unified-search-plugin", - "@kbn/securitysolution-io-ts-list-types", - "@kbn/securitysolution-list-constants", - "@kbn/securitysolution-list-hooks", - "@kbn/securitysolution-list-api", - "@kbn/securitysolution-lists-common", - "@kbn/securitysolution-exceptions-common", - "@kbn/securitysolution-endpoint-exceptions-common", - "@kbn/kibana-react-plugin", - "@kbn/i18n", - "@kbn/data-plugin", - "@kbn/securitysolution-list-utils", - "@kbn/securitysolution-utils", - "@kbn/es-query", - "@kbn/i18n-react", - "@kbn/securitysolution-autocomplete", - "@kbn/config-schema", - "@kbn/securitysolution-io-ts-utils", - "@kbn/core-http-server", - "@kbn/securitysolution-es-utils", - "@kbn/securitysolution-io-ts-types", - "@kbn/std", - "@kbn/utils", - "@kbn/logging-mocks", - "@kbn/utility-types", - "@kbn/core-elasticsearch-client-server-mocks", - "@kbn/core-saved-objects-server", - "@kbn/zod-helpers", - "@kbn/core-security-server", - "@kbn/core-http-server-mocks", - "@kbn/core-http-server-utils" - ], - "exclude": ["target/**/*"] -} diff --git a/x-pack/plugins/observability_solution/apm/public/hooks/use_entity_centric_experience_setting.tsx b/x-pack/plugins/observability_solution/apm/public/hooks/use_entity_centric_experience_setting.tsx index 32e68c40788fc..e5290bb25dbba 100644 --- a/x-pack/plugins/observability_solution/apm/public/hooks/use_entity_centric_experience_setting.tsx +++ b/x-pack/plugins/observability_solution/apm/public/hooks/use_entity_centric_experience_setting.tsx @@ -13,7 +13,7 @@ export function useEntityCentricExperienceSetting() { const isEntityCentricExperienceEnabled = core.uiSettings.get( entityCentricExperience, - true + false ); return { isEntityCentricExperienceEnabled }; diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_entity_centric_experience_setting.tsx b/x-pack/plugins/observability_solution/infra/public/hooks/use_entity_centric_experience_setting.tsx index 1cbc4680405e4..1ac6eed88f2ad 100644 --- a/x-pack/plugins/observability_solution/infra/public/hooks/use_entity_centric_experience_setting.tsx +++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_entity_centric_experience_setting.tsx @@ -11,7 +11,7 @@ import { useKibanaContextForPlugin } from './use_kibana'; export function useEntityCentricExperienceSetting() { const { uiSettings } = useKibanaContextForPlugin().services; - const isEntityCentricExperienceEnabled = uiSettings.get(entityCentricExperience, true); + const isEntityCentricExperienceEnabled = uiSettings.get(entityCentricExperience); return { isEntityCentricExperienceEnabled }; } diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.test.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.test.ts index 75048ac22a6a8..4a1466b698c78 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.test.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.test.ts @@ -35,13 +35,13 @@ describe('getDataStreamTypes', () => { jest.clearAllMocks(); }); - it('should return only metrics when entityCentriExperienceEnabled is false and hasMetricsData is true', async () => { + it('should return only metrics when entityCentricExperienceEnabled is false and hasMetricsData is true', async () => { (getHasMetricsData as jest.Mock).mockResolvedValue(true); const params = { entityId: 'entity123', entityType: 'host' as EntityType, - entityCentriExperienceEnabled: false, + entityCentricExperienceEnabled: false, infraMetricsClient, obsEsClient, entityManagerClient, @@ -58,13 +58,13 @@ describe('getDataStreamTypes', () => { }); }); - it('should return an empty array when entityCentriExperienceEnabled is false and hasMetricsData is false', async () => { + it('should return an empty array when entityCentricExperienceEnabled is false and hasMetricsData is false', async () => { (getHasMetricsData as jest.Mock).mockResolvedValue(false); const params = { entityId: 'entity123', entityType: 'container' as EntityType, - entityCentriExperienceEnabled: false, + entityCentricExperienceEnabled: false, infraMetricsClient, obsEsClient, entityManagerClient, @@ -75,7 +75,7 @@ describe('getDataStreamTypes', () => { expect(result).toEqual([]); }); - it('should return metrics and entity source_data_stream types when entityCentriExperienceEnabled is true and has entity data', async () => { + it('should return metrics and entity source_data_stream types when entityCentricExperienceEnabled is true and has entity data', async () => { (getHasMetricsData as jest.Mock).mockResolvedValue(true); (getLatestEntity as jest.Mock).mockResolvedValue({ sourceDataStreamType: ['logs', 'metrics'], @@ -84,7 +84,7 @@ describe('getDataStreamTypes', () => { const params = { entityId: 'entity123', entityType: 'host' as EntityType, - entityCentriExperienceEnabled: true, + entityCentricExperienceEnabled: true, infraMetricsClient, obsEsClient, entityManagerClient, @@ -104,14 +104,14 @@ describe('getDataStreamTypes', () => { }); }); - it('should return only metrics when entityCentriExperienceEnabled is true but entity data is undefined', async () => { + it('should return only metrics when entityCentricExperienceEnabled is true but entity data is undefined', async () => { (getHasMetricsData as jest.Mock).mockResolvedValue(true); (getLatestEntity as jest.Mock).mockResolvedValue(undefined); const params = { entityId: 'entity123', entityType: 'host' as EntityType, - entityCentriExperienceEnabled: true, + entityCentricExperienceEnabled: true, infraMetricsClient, obsEsClient, entityManagerClient, @@ -131,7 +131,7 @@ describe('getDataStreamTypes', () => { const params = { entityId: 'entity123', entityType: 'host' as EntityType, - entityCentriExperienceEnabled: true, + entityCentricExperienceEnabled: true, infraMetricsClient, obsEsClient, entityManagerClient, diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.ts index 4a949de4d0ed7..d1cd99be31f9f 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_data_stream_types.ts @@ -18,7 +18,7 @@ import { getLatestEntity } from './get_latest_entity'; interface Params { entityId: string; entityType: 'host' | 'container'; - entityCentriExperienceEnabled: boolean; + entityCentricExperienceEnabled: boolean; infraMetricsClient: InfraMetricsClient; obsEsClient: ObservabilityElasticsearchClient; entityManagerClient: EntityClient; @@ -26,7 +26,7 @@ interface Params { } export async function getDataStreamTypes({ - entityCentriExperienceEnabled, + entityCentricExperienceEnabled, entityId, entityManagerClient, entityType, @@ -42,7 +42,7 @@ export async function getDataStreamTypes({ const sourceDataStreams = new Set(hasMetricsData ? [EntityDataStreamType.METRICS] : []); - if (!entityCentriExperienceEnabled) { + if (!entityCentricExperienceEnabled) { return Array.from(sourceDataStreams); } diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts index 4056faba9427e..9c5c5c4527fee 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts @@ -54,13 +54,13 @@ export const initEntitiesConfigurationRoutes = (libs: InfraBackendLibs) => { plugin: `@kbn/${METRICS_APP_ID}-plugin`, }); - const entityCentriExperienceEnabled = await coreContext.uiSettings.client.get( + const entityCentricExperienceEnabled = await coreContext.uiSettings.client.get( entityCentricExperience ); try { const sourceDataStreamTypes = await getDataStreamTypes({ - entityCentriExperienceEnabled, + entityCentricExperienceEnabled, entityId, entityManagerClient, entityType, diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/alert_count/alert_count.cy.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/alert_count/alert_count.cy.ts index ac5fa17ecb08a..525828de10b18 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/alert_count/alert_count.cy.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/alert_count/alert_count.cy.ts @@ -33,10 +33,15 @@ const verifyAlertsTableCount = (alertsCount: string) => { verifyNumber(cy.getByTestSubj('toolbar-alerts-count'), alertsCount); }; -describe('Alert count', () => { +// Temporary skipping those test, will be enabled in the future once we fix them https://github.com/elastic/kibana/issues/204558 +describe.skip('Alert count', () => { beforeEach(() => { cy.loginAsSuperUser(); + cy.updateAdvancedSettings({ + 'observability:entityCentricExperience': true, + }); + cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); @@ -49,6 +54,9 @@ describe('Alert count', () => { }); afterEach(() => { + cy.updateAdvancedSettings({ + 'observability:entityCentricExperience': false, + }); entitiesSynthtrace.clean(); cleanEntityAlerts(); }); diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts index c2e7f1232e6aa..e86c673c2a6b7 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts @@ -11,9 +11,29 @@ import { generateEntities, generateLogs, generateTraces } from './generate_data' const start = '2024-10-16T00:00:00.000Z'; const end = '2024-10-16T00:15:00.000Z'; -describe('Home page', () => { +// Temporary skipping those test, will be enabled in the future once we fix them https://github.com/elastic/kibana/issues/204558 +describe.skip('Home page', () => { beforeEach(() => { cy.loginAsSuperUser(); + cy.updateAdvancedSettings({ + 'observability:entityCentricExperience': true, + }); + }); + + afterEach(() => { + cy.updateAdvancedSettings({ + 'observability:entityCentricExperience': false, + }); + }); + + describe('When the entityCentricExperience FF is disabled', () => { + it('Shows 404', () => { + cy.updateAdvancedSettings({ + 'observability:entityCentricExperience': false, + }); + cy.visitKibana('/app/inventory'); + cy.contains('Application Not Found'); + }); }); describe('When EEM is disabled', () => { diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts index c3462f8b6ff18..9a260519c7608 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts @@ -55,3 +55,17 @@ Cypress.Commands.add( ); } ); + +Cypress.Commands.add('updateAdvancedSettings', (settings: Record) => { + const kibanaUrl = Cypress.env('KIBANA_URL'); + cy.request({ + log: false, + method: 'POST', + url: `${kibanaUrl}/internal/kibana/settings`, + body: { changes: settings }, + headers: { + 'kbn-xsrf': 'e2e_test', + }, + auth: { user: 'elastic', pass: 'changeme' }, + }); +}); diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/types.d.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/types.d.ts index c51b20c3b9904..8e49da093612f 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/types.d.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/types.d.ts @@ -13,6 +13,7 @@ declare namespace Cypress { password: string; }): Cypress.Chainable>; getByTestSubj(selector: string): Chainable>; + updateAdvancedSettings(settings: Record): void; visitKibana(url: string): void; } } diff --git a/x-pack/plugins/observability_solution/inventory/public/plugin.ts b/x-pack/plugins/observability_solution/inventory/public/plugin.ts index 109123859d4ca..0d9309d3694fb 100644 --- a/x-pack/plugins/observability_solution/inventory/public/plugin.ts +++ b/x-pack/plugins/observability_solution/inventory/public/plugin.ts @@ -57,7 +57,7 @@ export class InventoryPlugin const inventoryAPIClient = createCallInventoryAPI(coreSetup); const isEntityCentricExperienceSettingEnabled = coreSetup.uiSettings.get( 'observability:entityCentricExperience', - true + false ); this.telemetry.setup({ diff --git a/x-pack/plugins/screenshotting/README.md b/x-pack/plugins/screenshotting/README.md deleted file mode 100644 index 8138be53dc8f4..0000000000000 --- a/x-pack/plugins/screenshotting/README.md +++ /dev/null @@ -1,156 +0,0 @@ -# Kibana Screenshotting - -This plugin provides functionality to take screenshots of the Kibana pages. -It uses Chromium and Puppeteer underneath to run the browser in headless mode. - -## Capabilities -- Canvas workpads screenshots. -- Dashboards screenshots. -- Expressions screenshots. -- PDF generation. -- Batch screenshotting. - -## Usage - -### Getting started -After listing the `screenshotting` plugin in your dependencies, the plugin will be intitalized on the setup stage. -The intitalization process downloads (if it is not already present) and verifies the Chromium build. - -The start contract exposes a public API to interact with the plugin. -Apart from the actual screenshotting functionality, it also provides a way for self-diagnostics. - -Here is an example of how you can take a screenshot of a Kibana URL. - -```typescript -import { lastValueFrom } from 'rxjs'; -import type { CoreSetup, Plugin } from 'src/core/server'; -import type { ScreenshottingStart } from 'x-pack/plugins/screenshotting/server'; - - -interface StartDeps { - screenshotting: ScreenshottingStart; -} - -class ExamplePlugin implements Plugin { - setup({ http, getStartServices }: CoreSetup) { - const router = http.createRouter(); - - router.get( - { - path: '/api/capture', - validate: { - query: schema.object({ - id: schema.string(), - }), - }, - }, - async (context, request, response) => { - const [, { screenshotting }] = await getStartServices(); - const { metrics, results } = await lastValueFrom( - screenshotting.getScreenshots({ - request, - urls: [`http://localhost/app/canvas#/workpad/workpad-${request.query.id}`], - }) - ); - - return response.ok({ - body: JSON.stringify({ - metrics, - image: results[0]?.screenshots[0]?.data.toString('base64'), - errors: results[0]?.renderErrors, - } as ScreenshottingExpressionResponse), - }); - } - ); - } - - start() {} -} - -export function plugin() { - return new ExamplePlugin(); -} -``` - -### API -Please use automatically generated API reference or generated TypeDoc comments to find the complete documentation. - -#### `getScreenshots(options): Observable` -Takes screenshots of multiple pages or an expression and returns an observable with the screenshotting results. - -The `options` parameter is an object with parameters of the screenshotting session. -Option | Required | Default | Description ---- | :---: | --- | --- -`browserTimezone` | no | _none_ | The browser timezone that will be emulated in the browser instance. This option should be used to keep timezone on server and client in sync. -`expression` | no | _none_ | An expression to capture screenshot of. Mutually exclusive with the `urls` parameter. -`format` | no | `'png'` | An output format. It can either be PDF or PNG. In case of capturing multiple URLs, all the screenshots will be combined into one document for PDF format. For PNG format, an array of screenshots will be returned. -`headers` | no | _none_ | Custom headers to be sent with each request. The headers will be used for authorization. -`input` | no | `undefined` | The expression input. -`layout` | no | `{}` | Page layout parameters describing characteristics of the capturing screenshot (e.g., dimensions, zoom, etc.). -`request` | no | _none_ | Kibana Request reference to extract headers from. -`timeouts` | no | _none_ | Timeouts for each phase of the screenshot. -`timeouts.openUrl` | no | (kibana.yml setting) | The timeout in milliseconds to allow the Chromium browser to wait for the "Loading…" screen to dismiss and find the initial data for the page. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. -`timeouts.renderComplete` | no | (kibana.yml setting) | The timeout in milliseconds to allow the Chromium browser to wait for all visualizations to fetch and render the data. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. -`timeouts.waitForElements` | no | (kibana.yml setting) | The timeout in milliseconds to allow the Chromium browser to wait for all visualization panels to load on the page. If the time is exceeded, a screenshot is captured showing the current page, and the result structure contains an error message. -`urls` | no | `[]` | The list or URL to take screenshots of. Every item can either be a string or a tuple containing a URL and a context. The contextual data can be gathered using the screenshot mode plugin. Mutually exclusive with the `expression` parameter. - -#### `diagnose(flags?: string[]): Observable` -Runs browser diagnostics. -The diagnostic implementation launches Chromium and emits the output in the resulting observable. - -There is a way to override some Chromium command line arguments using the `flags` parameter. - -### Configuration -Option | Default | Description ---- | --- | --- -`xpack.screenshotting.networkPolicy.enabled` | `true` | Capturing a screenshot from a Kibana page involves sending out requests for all the linked web assets. For example, a Markdown visualization can show an image from a remote server. -`xpack.screenshotting.networkPolicy.rules` | Allow http, https, ws, wss, and data. | A policy is specified as an array of objects that describe what to allow or deny based on a host or protocol. If a host or protocol is not specified, the rule matches any host or protocol. -`xpack.screenshotting.browser.autoDownload` | Depends on the `dist` parameter. | Flag to automatically download chromium distribution. -`xpack.screenshotting.browser.chromium.disableSandbox` | Defaults to `false` for all operating systems except Debian and Red Hat Linux, which use `true`. | It is recommended that you research the feasibility of enabling unprivileged user namespaces. An exception is if you are running Kibana in Docker because the container runs in a user namespace with the built-in seccomp/bpf filters. For more information, refer to [Chromium sandbox](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/linux/sandboxing.md). -`xpack.screenshotting.browser.chromium.proxy.enabled` | `false` | Enables the proxy for Chromium to use. -`xpack.screenshotting.browser.chromium.proxy.server` | _none_ | The uri for the proxy server. Providing the username and password for the proxy server via the uri is not supported. -`xpack.screenshotting.browser.chromium.proxy.bypass` | `[]` | An array of hosts that should not go through the proxy server and should use a direct connection instead. Examples of valid entries are "elastic.co", "*.elastic.co", ".elastic.co", ".elastic.co:5601". - -## How It Works -```mermaid -sequenceDiagram - participant User - participant Screenshotting - participant Browser - - User ->> Screenshotting: API call - Screenshotting ->> Browser: Launch browser - activate Browser - Screenshotting ->> Browser: Create page - Screenshotting ->> Browser: Set parameters - Note over Screenshotting,Browser: timezone - - Screenshotting ->> Browser: Open URL - Screenshotting ->> Browser: Set contextual data - Note over Screenshotting,Browser: custom context, screenshot mode flag - Browser ->> Screenshotting: Rendering - - Screenshotting ->> Browser: Wait for visualizations - Note over Screenshotting,Browser: poll for a number of DOM nodes to match
the number of dashboard elements - Screenshotting ->> Browser: Wait for render completion - Note over Screenshotting,Browser: poll for selectors indicating rendering completion - Browser ->> Screenshotting: Page is ready - - Screenshotting ->> Browser: Take screenshot - Browser ->> Screenshotting: Return PNG buffer - Screenshotting ->> User: Return screenshot -``` - -## Testing -### Integration -There is an example plugin that demonstrates integration with the screenshotting plugin. That plugin utilizes expression capturing. - -### Chromium Downloads -To download all Chromium browsers for all platforms and architectures: - -```bash -cd x-pack -npx gulp downloadChromium -``` - -This command is used to provision CI workspaces so that Chromium does not need to be downloaded for every CI run. diff --git a/x-pack/plugins/screenshotting/jest.config.js b/x-pack/plugins/screenshotting/jest.config.js deleted file mode 100644 index a02d667f86a19..0000000000000 --- a/x-pack/plugins/screenshotting/jest.config.js +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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. - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../../..', - roots: ['/x-pack/plugins/screenshotting'], - coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/screenshotting', - coverageReporters: ['text', 'html'], - collectCoverageFrom: ['/x-pack/plugins/screenshotting/server/**/*.{ts}'], -}; diff --git a/x-pack/plugins/screenshotting/tsconfig.json b/x-pack/plugins/screenshotting/tsconfig.json deleted file mode 100644 index 5e37b84bbf2e9..0000000000000 --- a/x-pack/plugins/screenshotting/tsconfig.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - }, - "include": [ - "common/**/*", - "public/**/*", - "server/**/*", - "../../../typings/**/*" - ], - "kbn_references": [ - "@kbn/core", - { "path": "../../../src/setup_node_env/tsconfig.json" }, - "@kbn/expressions-plugin", - "@kbn/screenshot-mode-plugin", - "@kbn/cloud-plugin", - "@kbn/utility-types", - "@kbn/logging", - "@kbn/std", - "@kbn/i18n", - "@kbn/utils", - "@kbn/core-logging-server-mocks", - "@kbn/logging-mocks", - "@kbn/core-http-server", - "@kbn/core-plugins-server", - "@kbn/task-manager-plugin", - "@kbn/screenshotting-server", - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/x-pack/plugins/search_notebooks/public/components/notebooks_button.tsx b/x-pack/plugins/search_notebooks/public/components/notebooks_button.tsx index 66fc50a03ddd7..d71cade82aae7 100644 --- a/x-pack/plugins/search_notebooks/public/components/notebooks_button.tsx +++ b/x-pack/plugins/search_notebooks/public/components/notebooks_button.tsx @@ -30,7 +30,7 @@ export const SearchNotebooksButton = ({ if (activeView) { return ( div { padding-bottom: 0; padding-top: 0; @@ -13,4 +9,4 @@ .serverlessSearchCloudDetailsCopyPanel { word-break: break-all; -} \ No newline at end of file +} diff --git a/x-pack/plugins/serverless_search/public/application/components/overview.tsx b/x-pack/plugins/serverless_search/public/application/components/overview.tsx index 678eadb6b5cb6..d20706a6aa804 100644 --- a/x-pack/plugins/serverless_search/public/application/components/overview.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/overview.tsx @@ -14,7 +14,6 @@ import { EuiIcon, EuiPageTemplate, EuiPanel, - EuiText, EuiBadge, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -96,9 +95,7 @@ export const ElasticsearchOverview = () => { return ( - - - + ; @@ -35,9 +35,10 @@ export type CrowdstrikeGetAgentOnlineStatusResponse = TypeOf< typeof CrowdstrikeGetAgentOnlineStatusResponseSchema >; export type CrowdstrikeGetTokenResponse = TypeOf; -export type CrowdstrikeInitRTRResponse = TypeOf; export type CrowdstrikeHostActionsParams = TypeOf; export type CrowdstrikeActionParams = TypeOf; export type CrowdstrikeInitRTRParams = TypeOf; + +export type CrowdStrikeExecuteRTRResponse = TypeOf; diff --git a/x-pack/plugins/stack_connectors/common/inference/constants.ts b/x-pack/plugins/stack_connectors/common/inference/constants.ts index b795e54f5d32a..c2f2e6713270b 100644 --- a/x-pack/plugins/stack_connectors/common/inference/constants.ts +++ b/x-pack/plugins/stack_connectors/common/inference/constants.ts @@ -32,6 +32,9 @@ export enum ServiceProviderKeys { export const INFERENCE_CONNECTOR_ID = '.inference'; export enum SUB_ACTION { + UNIFIED_COMPLETION_ASYNC_ITERATOR = 'unified_completion_async_iterator', + UNIFIED_COMPLETION_STREAM = 'unified_completion_stream', + UNIFIED_COMPLETION = 'unified_completion', COMPLETION = 'completion', RERANK = 'rerank', TEXT_EMBEDDING = 'text_embedding', diff --git a/x-pack/plugins/stack_connectors/common/inference/schema.ts b/x-pack/plugins/stack_connectors/common/inference/schema.ts index 07b51cf9a5aa3..c62e9782bb517 100644 --- a/x-pack/plugins/stack_connectors/common/inference/schema.ts +++ b/x-pack/plugins/stack_connectors/common/inference/schema.ts @@ -23,6 +23,176 @@ export const ChatCompleteParamsSchema = schema.object({ input: schema.string(), }); +// subset of OpenAI.ChatCompletionMessageParam https://github.com/openai/openai-node/blob/master/src/resources/chat/completions.ts +const AIMessage = schema.object({ + role: schema.string(), + content: schema.maybe(schema.string()), + name: schema.maybe(schema.string()), + tool_calls: schema.maybe( + schema.arrayOf( + schema.object({ + id: schema.string(), + function: schema.object({ + arguments: schema.maybe(schema.string()), + name: schema.maybe(schema.string()), + }), + type: schema.string(), + }) + ) + ), + tool_call_id: schema.maybe(schema.string()), +}); + +const AITool = schema.object({ + type: schema.string(), + function: schema.object({ + name: schema.string(), + description: schema.maybe(schema.string()), + parameters: schema.maybe(schema.recordOf(schema.string(), schema.any())), + }), +}); + +// subset of OpenAI.ChatCompletionCreateParamsBase https://github.com/openai/openai-node/blob/master/src/resources/chat/completions.ts +export const UnifiedChatCompleteParamsSchema = schema.object({ + body: schema.object({ + messages: schema.arrayOf(AIMessage, { defaultValue: [] }), + model: schema.maybe(schema.string()), + /** + * The maximum number of [tokens](/tokenizer) that can be generated in the chat + * completion. This value can be used to control + * [costs](https://openai.com/api/pricing/) for text generated via API. + * + * This value is now deprecated in favor of `max_completion_tokens`, and is not + * compatible with + * [o1 series models](https://platform.openai.com/docs/guides/reasoning). + */ + max_tokens: schema.maybe(schema.number()), + /** + * Developer-defined tags and values used for filtering completions in the + * [dashboard](https://platform.openai.com/chat-completions). + */ + metadata: schema.maybe(schema.recordOf(schema.string(), schema.string())), + /** + * How many chat completion choices to generate for each input message. Note that + * you will be charged based on the number of generated tokens across all of the + * choices. Keep `n` as `1` to minimize costs. + */ + n: schema.maybe(schema.number()), + /** + * Up to 4 sequences where the API will stop generating further tokens. + */ + stop: schema.maybe( + schema.nullable(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])) + ), + /** + * What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + * make the output more random, while lower values like 0.2 will make it more + * focused and deterministic. + * + * We generally recommend altering this or `top_p` but not both. + */ + temperature: schema.maybe(schema.number()), + /** + * Controls which (if any) tool is called by the model. `none` means the model will + * not call any tool and instead generates a message. `auto` means the model can + * pick between generating a message or calling one or more tools. `required` means + * the model must call one or more tools. Specifying a particular tool via + * `{"type": "function", "function": {"name": "my_function"}}` forces the model to + * call that tool. + * + * `none` is the default when no tools are present. `auto` is the default if tools + * are present. + */ + tool_choice: schema.maybe( + schema.oneOf([ + schema.string(), + schema.object({ + type: schema.string(), + function: schema.object({ + name: schema.string(), + }), + }), + ]) + ), + /** + * A list of tools the model may call. Currently, only functions are supported as a + * tool. Use this to provide a list of functions the model may generate JSON inputs + * for. A max of 128 functions are supported. + */ + tools: schema.maybe(schema.arrayOf(AITool)), + /** + * An alternative to sampling with temperature, called nucleus sampling, where the + * model considers the results of the tokens with top_p probability mass. So 0.1 + * means only the tokens comprising the top 10% probability mass are considered. + * + * We generally recommend altering this or `temperature` but not both. + */ + top_p: schema.maybe(schema.number()), + /** + * A unique identifier representing your end-user, which can help OpenAI to monitor + * and detect abuse. + * [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids). + */ + user: schema.maybe(schema.string()), + }), + // abort signal from client + signal: schema.maybe(schema.any()), +}); + +export const UnifiedChatCompleteResponseSchema = schema.object({ + id: schema.string(), + choices: schema.arrayOf( + schema.object({ + finish_reason: schema.maybe( + schema.nullable( + schema.oneOf([ + schema.literal('stop'), + schema.literal('length'), + schema.literal('tool_calls'), + schema.literal('content_filter'), + schema.literal('function_call'), + ]) + ) + ), + index: schema.maybe(schema.number()), + message: schema.object({ + content: schema.maybe(schema.nullable(schema.string())), + refusal: schema.maybe(schema.nullable(schema.string())), + role: schema.maybe(schema.string()), + tool_calls: schema.maybe( + schema.arrayOf( + schema.object({ + id: schema.maybe(schema.string()), + index: schema.maybe(schema.number()), + function: schema.maybe( + schema.object({ + arguments: schema.maybe(schema.string()), + name: schema.maybe(schema.string()), + }) + ), + type: schema.maybe(schema.string()), + }), + { defaultValue: [] } + ) + ), + }), + }), + { defaultValue: [] } + ), + created: schema.maybe(schema.number()), + model: schema.maybe(schema.string()), + object: schema.maybe(schema.string()), + usage: schema.maybe( + schema.nullable( + schema.object({ + completion_tokens: schema.maybe(schema.number()), + prompt_tokens: schema.maybe(schema.number()), + total_tokens: schema.maybe(schema.number()), + }) + ) + ), +}); + export const ChatCompleteResponseSchema = schema.arrayOf( schema.object({ result: schema.string(), @@ -66,3 +236,12 @@ export const TextEmbeddingResponseSchema = schema.arrayOf( ); export const StreamingResponseSchema = schema.stream(); + +// Run action schema +export const DashboardActionParamsSchema = schema.object({ + dashboardId: schema.string(), +}); + +export const DashboardActionResponseSchema = schema.object({ + available: schema.boolean(), +}); diff --git a/x-pack/plugins/stack_connectors/common/inference/types.ts b/x-pack/plugins/stack_connectors/common/inference/types.ts index d8b846ce19422..1593429792e07 100644 --- a/x-pack/plugins/stack_connectors/common/inference/types.ts +++ b/x-pack/plugins/stack_connectors/common/inference/types.ts @@ -18,12 +18,19 @@ import { SparseEmbeddingResponseSchema, TextEmbeddingParamsSchema, TextEmbeddingResponseSchema, + UnifiedChatCompleteParamsSchema, + UnifiedChatCompleteResponseSchema, + DashboardActionParamsSchema, + DashboardActionResponseSchema, } from './schema'; import { ConfigProperties } from '../dynamic_config/types'; export type Config = TypeOf; export type Secrets = TypeOf; +export type UnifiedChatCompleteParams = TypeOf; +export type UnifiedChatCompleteResponse = TypeOf; + export type ChatCompleteParams = TypeOf; export type ChatCompleteResponse = TypeOf; @@ -38,6 +45,9 @@ export type TextEmbeddingResponse = TypeOf; export type StreamingResponse = TypeOf; +export type DashboardActionParams = TypeOf; +export type DashboardActionResponse = TypeOf; + export type FieldsConfiguration = Record; export interface InferenceProvider { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/constants.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/constants.tsx index 8427caaf49ffc..1b635ca8fe887 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/constants.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/constants.tsx @@ -25,13 +25,27 @@ export const DEFAULT_TEXT_EMBEDDING_BODY = { inputType: 'ingest', }; +export const DEFAULT_UNIFIED_CHAT_COMPLETE_BODY = { + body: { + messages: [ + { + role: 'user', + content: 'Hello world', + }, + ], + }, +}; + export const DEFAULTS_BY_TASK_TYPE: Record = { [SUB_ACTION.COMPLETION]: DEFAULT_CHAT_COMPLETE_BODY, + [SUB_ACTION.UNIFIED_COMPLETION]: DEFAULT_UNIFIED_CHAT_COMPLETE_BODY, + [SUB_ACTION.UNIFIED_COMPLETION_STREAM]: DEFAULT_UNIFIED_CHAT_COMPLETE_BODY, + [SUB_ACTION.UNIFIED_COMPLETION_ASYNC_ITERATOR]: DEFAULT_UNIFIED_CHAT_COMPLETE_BODY, [SUB_ACTION.RERANK]: DEFAULT_RERANK_BODY, [SUB_ACTION.SPARSE_EMBEDDING]: DEFAULT_SPARSE_EMBEDDING_BODY, [SUB_ACTION.TEXT_EMBEDDING]: DEFAULT_TEXT_EMBEDDING_BODY, }; -export const DEFAULT_TASK_TYPE = 'completion'; +export const DEFAULT_TASK_TYPE = 'unified_completion'; export const DEFAULT_PROVIDER = 'elasticsearch'; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/inference.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/inference.test.tsx index 76dc50a316e65..b67264674aebe 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/inference.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/inference.test.tsx @@ -44,8 +44,16 @@ describe('OpenAI action params validation', () => { subActionParams: { input: ['message test'], query: 'foobar' }, }, { - subAction: SUB_ACTION.COMPLETION, - subActionParams: { input: 'message test' }, + subAction: SUB_ACTION.UNIFIED_COMPLETION, + subActionParams: { body: { messages: [{ role: 'user', content: 'What is Elastic?' }] } }, + }, + { + subAction: SUB_ACTION.UNIFIED_COMPLETION_STREAM, + subActionParams: { body: { messages: [{ role: 'user', content: 'What is Elastic?' }] } }, + }, + { + subAction: SUB_ACTION.UNIFIED_COMPLETION_ASYNC_ITERATOR, + subActionParams: { body: { messages: [{ role: 'user', content: 'What is Elastic?' }] } }, }, { subAction: SUB_ACTION.TEXT_EMBEDDING, @@ -55,6 +63,10 @@ describe('OpenAI action params validation', () => { subAction: SUB_ACTION.SPARSE_EMBEDDING, subActionParams: { input: 'message test' }, }, + { + subAction: SUB_ACTION.COMPLETION, + subActionParams: { input: 'message test' }, + }, ])( 'validation succeeds when params are valid for subAction $subAction', async ({ subAction, subActionParams }) => { @@ -63,19 +75,25 @@ describe('OpenAI action params validation', () => { subActionParams, }; expect(await actionTypeModel.validateParams(actionParams)).toEqual({ - errors: { input: [], subAction: [], inputType: [], query: [] }, + errors: { body: [], input: [], subAction: [], inputType: [], query: [] }, }); } ); test('params validation fails when params is a wrong object', async () => { const actionParams = { - subAction: SUB_ACTION.COMPLETION, + subAction: SUB_ACTION.UNIFIED_COMPLETION, subActionParams: { body: 'message {test}' }, }; expect(await actionTypeModel.validateParams(actionParams)).toEqual({ - errors: { input: ['Input is required.'], inputType: [], query: [], subAction: [] }, + errors: { + body: ['Messages is required.'], + inputType: [], + query: [], + subAction: [], + input: [], + }, }); }); @@ -86,6 +104,7 @@ describe('OpenAI action params validation', () => { expect(await actionTypeModel.validateParams(actionParams)).toEqual({ errors: { + body: [], input: [], inputType: [], query: [], @@ -102,6 +121,7 @@ describe('OpenAI action params validation', () => { expect(await actionTypeModel.validateParams(actionParams)).toEqual({ errors: { + body: [], input: [], inputType: [], query: [], @@ -118,6 +138,7 @@ describe('OpenAI action params validation', () => { expect(await actionTypeModel.validateParams(actionParams)).toEqual({ errors: { + body: [], input: ['Input is required.', 'Input does not have a valid Array format.'], inputType: [], query: ['Query is required.'], @@ -134,6 +155,7 @@ describe('OpenAI action params validation', () => { expect(await actionTypeModel.validateParams(actionParams)).toEqual({ errors: { + body: [], input: [], inputType: ['Input type is required.'], query: [], diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/inference.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/inference.tsx index e16d03306c166..388da0556801c 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/inference.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/inference.tsx @@ -19,6 +19,7 @@ import { InferenceActionParams, InferenceConnector } from './types'; interface ValidationErrors { subAction: string[]; input: string[]; + body: string[]; // rerank only query: string[]; // text_embedding only @@ -40,14 +41,28 @@ export function getConnectorType(): InferenceConnector { const translations = await import('./translations'); const errors: ValidationErrors = { input: [], + body: [], subAction: [], inputType: [], query: [], }; if ( - subAction === SUB_ACTION.RERANK || + subAction === SUB_ACTION.UNIFIED_COMPLETION || + subAction === SUB_ACTION.UNIFIED_COMPLETION_STREAM || + subAction === SUB_ACTION.UNIFIED_COMPLETION_ASYNC_ITERATOR + ) { + if ( + !Array.isArray(subActionParams.body.messages) || + !subActionParams.body.messages.length + ) { + errors.body.push(translations.getRequiredMessage('Messages')); + } + } + + if ( subAction === SUB_ACTION.COMPLETION || + subAction === SUB_ACTION.RERANK || subAction === SUB_ACTION.TEXT_EMBEDDING || subAction === SUB_ACTION.SPARSE_EMBEDDING ) { @@ -76,10 +91,13 @@ export function getConnectorType(): InferenceConnector { errors.subAction.push(translations.getRequiredMessage('Action')); } else if ( ![ - SUB_ACTION.COMPLETION, + SUB_ACTION.UNIFIED_COMPLETION, + SUB_ACTION.UNIFIED_COMPLETION_STREAM, + SUB_ACTION.UNIFIED_COMPLETION_ASYNC_ITERATOR, SUB_ACTION.SPARSE_EMBEDDING, SUB_ACTION.RERANK, SUB_ACTION.TEXT_EMBEDDING, + SUB_ACTION.COMPLETION, ].includes(subAction) ) { errors.subAction.push(translations.INVALID_ACTION); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/params.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/params.test.tsx index 49773edc2246a..ba094ec64f6bd 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/params.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/params.test.tsx @@ -15,8 +15,8 @@ describe('Inference Params Fields renders', () => { const { getByTestId } = render( { index={0} /> ); - expect(getByTestId('inferenceInput')).toBeInTheDocument(); - expect(getByTestId('inferenceInput')).toHaveProperty('value', 'What is Elastic?'); + expect(getByTestId('inference-bodyJsonEditor')).toBeInTheDocument(); + expect(getByTestId('bodyJsonEditor')).toHaveProperty( + 'value', + `{\"messages\":[{\"role\":\"user\",\"content\":\"What is Elastic?\"}]}` + ); }); test.each(['openai', 'googleaistudio'])( @@ -76,15 +79,25 @@ describe('Inference Params Fields renders', () => { /> ); expect(editAction).toHaveBeenCalledTimes(2); - expect(editAction).toHaveBeenCalledWith('subAction', SUB_ACTION.COMPLETION, 0); if (provider === 'openai') { + expect(editAction).toHaveBeenCalledWith('subAction', SUB_ACTION.UNIFIED_COMPLETION, 0); expect(editAction).toHaveBeenCalledWith( 'subActionParams', - { input: 'What is Elastic?' }, + { + body: { + messages: [ + { + content: 'Hello world', + role: 'user', + }, + ], + }, + }, 0 ); } if (provider === 'googleaistudio') { + expect(editAction).toHaveBeenCalledWith('subAction', SUB_ACTION.COMPLETION, 0); expect(editAction).toHaveBeenCalledWith( 'subActionParams', { input: 'What is Elastic?' }, diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/params.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/params.tsx index c24fff24c33f6..be162e70493bc 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/params.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/params.tsx @@ -12,11 +12,13 @@ import { } from '@kbn/triggers-actions-ui-plugin/public'; import { EuiTextArea, EuiFormRow, EuiSpacer, EuiSelect } from '@elastic/eui'; import type { RuleFormParamsErrors } from '@kbn/response-ops-rule-form'; +import { ActionVariable } from '@kbn/alerting-types'; import { ChatCompleteParams, RerankParams, SparseEmbeddingParams, TextEmbeddingParams, + UnifiedChatCompleteParams, } from '../../../common/inference/types'; import { DEFAULTS_BY_TASK_TYPE } from './constants'; import * as i18n from './translations'; @@ -25,28 +27,38 @@ import { InferenceActionConnector, InferenceActionParams } from './types'; const InferenceServiceParamsFields: React.FunctionComponent< ActionParamsProps -> = ({ actionParams, editAction, index, errors, actionConnector }) => { +> = ({ actionParams, editAction, index, errors, actionConnector, messageVariables }) => { const { subAction, subActionParams } = actionParams; - const { taskType } = (actionConnector as unknown as InferenceActionConnector).config; + const { taskType, provider } = (actionConnector as unknown as InferenceActionConnector).config; useEffect(() => { if (!subAction) { - editAction('subAction', taskType, index); + editAction( + 'subAction', + provider === 'openai' && taskType === 'completion' + ? SUB_ACTION.UNIFIED_COMPLETION + : taskType, + index + ); } - }, [editAction, index, subAction, taskType]); + }, [editAction, index, provider, subAction, taskType]); useEffect(() => { if (!subActionParams) { editAction( 'subActionParams', { - ...(DEFAULTS_BY_TASK_TYPE[taskType] ?? {}), + ...(DEFAULTS_BY_TASK_TYPE[ + provider === 'openai' && taskType === 'completion' + ? SUB_ACTION.UNIFIED_COMPLETION + : taskType + ] ?? {}), }, index ); } - }, [editAction, index, subActionParams, taskType]); + }, [editAction, index, provider, subActionParams, taskType]); const editSubActionParams = useCallback( (params: Partial) => { @@ -55,6 +67,28 @@ const InferenceServiceParamsFields: React.FunctionComponent< [editAction, index, subActionParams] ); + if (subAction === SUB_ACTION.UNIFIED_COMPLETION) { + return ( + + ); + } + + if (subAction === SUB_ACTION.UNIFIED_COMPLETION_ASYNC_ITERATOR) { + return ( + + ); + } + if (subAction === SUB_ACTION.COMPLETION) { return ( ) => void; + messageVariables: ActionVariable[] | undefined; +}> = ({ subActionParams, editSubActionParams, errors, messageVariables }) => { + const { body } = subActionParams ?? {}; + + return ( + <> + { + editSubActionParams({ body: JSON.parse(json) }); + }} + onBlur={() => { + if (!subActionParams.body) { + editSubActionParams({ body: { messages: [] } }); + } + }} + dataTestSubj="inference-bodyJsonEditor" + /> + + ); +}; + const CompletionParamsFields: React.FunctionComponent<{ subActionParams: ChatCompleteParams; errors: RuleFormParamsErrors; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/types.ts b/x-pack/plugins/stack_connectors/public/connector_types/inference/types.ts index 1bd55793bc463..1756e213a1a7a 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/types.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/types.ts @@ -13,9 +13,16 @@ import { RerankParams, SparseEmbeddingParams, TextEmbeddingParams, + UnifiedChatCompleteParams, } from '../../../common/inference/types'; export type InferenceActionParams = + | { subAction: SUB_ACTION.UNIFIED_COMPLETION_STREAM; subActionParams: UnifiedChatCompleteParams } + | { subAction: SUB_ACTION.UNIFIED_COMPLETION; subActionParams: UnifiedChatCompleteParams } + | { + subAction: SUB_ACTION.UNIFIED_COMPLETION_ASYNC_ITERATOR; + subActionParams: UnifiedChatCompleteParams; + } | { subAction: SUB_ACTION.COMPLETION; subActionParams: ChatCompleteParams } | { subAction: SUB_ACTION.RERANK; subActionParams: RerankParams } | { subAction: SUB_ACTION.SPARSE_EMBEDDING; subActionParams: SparseEmbeddingParams } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts index 14b38b414eb3b..9bc53c58aa198 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts @@ -22,6 +22,7 @@ import type { CrowdstrikeGetTokenResponse, CrowdstrikeGetAgentOnlineStatusResponse, RelaxedCrowdstrikeBaseApiResponse, + CrowdStrikeExecuteRTRResponse, } from '../../../common/crowdstrike/types'; import { CrowdstrikeHostActionsParamsSchema, @@ -31,7 +32,6 @@ import { CrowdstrikeRTRCommandParamsSchema, CrowdstrikeExecuteRTRResponseSchema, CrowdstrikeGetScriptsParamsSchema, - CrowdStrikeExecuteRTRResponse, CrowdstrikeApiDoNotValidateResponsesSchema, CrowdstrikeGetTokenResponseSchema, } from '../../../common/crowdstrike/schema'; @@ -292,15 +292,9 @@ export class CrowdstrikeConnector extends SubActionConnector< payload: { command: string; endpoint_ids: string[]; - overwriteUrl?: 'batchExecuteRTR' | 'batchActiveResponderExecuteRTR' | 'batchAdminExecuteRTR'; }, connectorUsageCollector: ConnectorUsageCollector ): Promise => { - // Some commands are only available in specific API endpoints, however there's an additional requirement check for the command's argument - // Eg. runscript command is available with the batchExecuteRTR endpoint, but if it goes with --Raw parameter, it should go to batchAdminExecuteRTR endpoint - // This overwrite value will be coming from kibana response actions api - const csUrl = payload.overwriteUrl ? this.urls[payload.overwriteUrl] : url; - const batchId = await this.crowdStrikeSessionManager.initializeSession( { endpoint_ids: payload.endpoint_ids }, connectorUsageCollector @@ -313,7 +307,7 @@ export class CrowdstrikeConnector extends SubActionConnector< } return await this.crowdstrikeApiRequest( { - url: csUrl, + url, method: 'post', data: { base_command: baseCommand, @@ -335,7 +329,6 @@ export class CrowdstrikeConnector extends SubActionConnector< payload: { command: string; endpoint_ids: string[]; - overwriteUrl?: 'batchActiveResponderExecuteRTR' | 'batchAdminExecuteRTR'; }, connectorUsageCollector: ConnectorUsageCollector ): Promise { @@ -351,7 +344,6 @@ export class CrowdstrikeConnector extends SubActionConnector< payload: { command: string; endpoint_ids: string[]; - overwriteUrl?: 'batchAdminExecuteRTR'; }, connectorUsageCollector: ConnectorUsageCollector ): Promise { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/inference/helpers.ts b/x-pack/plugins/stack_connectors/server/connector_types/inference/helpers.ts new file mode 100644 index 0000000000000..7c6bfab9c6396 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/inference/helpers.ts @@ -0,0 +1,111 @@ +/* + * 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 { last, lastValueFrom, map, merge, Observable, scan, share } from 'rxjs'; +import type { Readable } from 'node:stream'; +import { createParser } from 'eventsource-parser'; +import { UnifiedChatCompleteResponse } from '../../../common/inference/types'; + +// TODO: Extract to the common package with appex-ai +export function eventSourceStreamIntoObservable(readable: Readable) { + return new Observable((subscriber) => { + const parser = createParser({ + onEvent: (event) => { + subscriber.next(event.data); + }, + }); + + async function processStream() { + for await (const chunk of readable) { + parser.feed(chunk.toString()); + } + } + + processStream().then( + () => { + subscriber.complete(); + }, + (error) => { + subscriber.error(error); + } + ); + }); +} + +export function chunksIntoMessage(obs$: Observable) { + const shared$ = obs$.pipe(share()); + + return lastValueFrom( + merge( + shared$, + shared$.pipe( + scan( + (prev, chunk) => { + if (chunk.choices.length > 0 && !chunk.usage) { + prev.choices[0].message.content += chunk.choices[0].message.content ?? ''; + + chunk.choices[0].message.tool_calls?.forEach((toolCall) => { + if (toolCall.index !== undefined) { + const prevToolCallLength = prev.choices[0].message.tool_calls?.length ?? 0; + if (prevToolCallLength - 1 !== toolCall.index) { + if (!prev.choices[0].message.tool_calls) { + prev.choices[0].message.tool_calls = []; + } + prev.choices[0].message.tool_calls.push({ + function: { + name: '', + arguments: '', + }, + id: '', + }); + } + const prevToolCall = prev.choices[0].message.tool_calls[toolCall.index]; + + if (toolCall.function?.name) { + prevToolCall.function.name += toolCall.function?.name; + } + if (toolCall.function?.arguments) { + prevToolCall.function.arguments += toolCall.function?.arguments; + } + if (toolCall.id) { + prevToolCall.id += toolCall.id; + } + if (toolCall.type) { + prevToolCall.type = toolCall.type; + } + } + }); + } else if (chunk.usage) { + prev.usage = chunk.usage; + } + return { ...prev, id: chunk.id, model: chunk.model }; + }, + { + choices: [ + { + message: { + content: '', + role: 'assistant', + }, + }, + ], + object: 'chat.completion', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any + ), + last(), + map((concatenatedChunk): UnifiedChatCompleteResponse => { + // TODO: const validatedToolCalls = validateToolCalls(concatenatedChunk.choices[0].message.tool_calls); + if (concatenatedChunk.choices[0].message.content === '') { + concatenatedChunk.choices[0].message.content = null; + } + return concatenatedChunk; + }) + ) + ) + ); +} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/inference/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/inference/index.ts index 18af48bc18a51..5af6773d15fe9 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/inference/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/inference/index.ts @@ -161,7 +161,10 @@ export const configValidator = (configObject: Config, validatorServices: Validat ); } - if (!Object.keys(SUB_ACTION).includes(taskType.toUpperCase())) { + if ( + !taskType.includes('completion') && + !Object.keys(SUB_ACTION).includes(taskType.toUpperCase()) + ) { throw new Error( `Task type is not supported${ taskType && taskType.length ? `: ${taskType}` : `` diff --git a/x-pack/plugins/stack_connectors/server/connector_types/inference/inference.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/inference/inference.test.ts index a79bd0360598b..4aa28d2952dba 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/inference/inference.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/inference/inference.test.ts @@ -9,7 +9,7 @@ import { InferenceConnector } from './inference'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; -import { PassThrough, Transform } from 'stream'; +import { Readable, Transform } from 'stream'; import {} from '@kbn/actions-plugin/server/types'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { InferenceInferenceResponse } from '@elastic/elasticsearch/lib/api/types'; @@ -29,7 +29,7 @@ describe('InferenceConnector', () => { ], }; - describe('performApiCompletion', () => { + describe('performApiUnifiedCompletion', () => { const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser; beforeEach(() => { @@ -60,28 +60,44 @@ describe('InferenceConnector', () => { }); it('uses the completion task_type is supplied', async () => { - const response = await connector.performApiCompletion({ - input: 'What is Elastic?', + const stream = Readable.from([ + `data: {"id":"chatcmpl-AbLKRuRMZCAcMMQdl96KMTUgAfZNg","choices":[{"delta":{"content":" you"},"index":0}],"model":"gpt-4o-2024-08-06","object":"chat.completion.chunk"}\n\n`, + `data: [DONE]\n\n`, + ]); + mockEsClient.transport.request.mockResolvedValue(stream); + + const response = await connector.performApiUnifiedCompletion({ + body: { messages: [{ content: 'What is Elastic?', role: 'user' }] }, }); - expect(mockEsClient.inference.inference).toBeCalledTimes(1); - expect(mockEsClient.inference.inference).toHaveBeenCalledWith( + expect(mockEsClient.transport.request).toBeCalledTimes(1); + expect(mockEsClient.transport.request).toHaveBeenCalledWith( { - inference_id: 'test', - input: 'What is Elastic?', - task_type: 'completion', + body: { + messages: [ + { + content: 'What is Elastic?', + role: 'user', + }, + ], + n: undefined, + }, + method: 'POST', + path: '_inference/completion/test/_unified', }, - { asStream: false } + { asStream: true } ); - expect(response).toEqual(mockResponse.completion); + expect(response.choices[0].message.content).toEqual(' you'); }); it('errors during API calls are properly handled', async () => { // @ts-ignore - mockEsClient.inference.inference = mockError; + mockEsClient.transport.request = mockError; - await expect(connector.performApiCompletion({ input: 'What is Elastic?' })).rejects.toThrow( - 'API Error' - ); + await expect( + connector.performApiUnifiedCompletion({ + body: { messages: [{ content: 'What is Elastic?', role: 'user' }] }, + }) + ).rejects.toThrow('API Error'); }); }); @@ -223,6 +239,7 @@ describe('InferenceConnector', () => { }; beforeEach(() => { + jest.clearAllMocks(); // @ts-ignore mockStream(); }); @@ -238,7 +255,7 @@ describe('InferenceConnector', () => { }, provider: 'elasticsearch', taskType: 'completion', - inferenceId: '', + inferenceId: 'test', taskTypeConfig: {}, }, secrets: { providerSecrets: {} }, @@ -247,13 +264,23 @@ describe('InferenceConnector', () => { }); it('the API call is successful with correct request parameters', async () => { - await connector.performApiCompletionStream({ input: 'Hello world' }); - expect(mockEsClient.inference.inference).toBeCalledTimes(1); - expect(mockEsClient.inference.inference).toHaveBeenCalledWith( + await connector.performApiUnifiedCompletionStream({ + body: { messages: [{ content: 'Hello world', role: 'user' }] }, + }); + expect(mockEsClient.transport.request).toBeCalledTimes(1); + expect(mockEsClient.transport.request).toHaveBeenCalledWith( { - inference_id: '', - input: 'Hello world', - task_type: 'completion', + body: { + messages: [ + { + content: 'Hello world', + role: 'user', + }, + ], + n: undefined, + }, + method: 'POST', + path: '_inference/completion/test/_unified', }, { asStream: true } ); @@ -261,32 +288,42 @@ describe('InferenceConnector', () => { it('signal is properly passed to streamApi', async () => { const signal = jest.fn() as unknown as AbortSignal; - await connector.performApiCompletionStream({ input: 'Hello world', signal }); + await connector.performApiUnifiedCompletionStream({ + body: { messages: [{ content: 'Hello world', role: 'user' }] }, + signal, + }); - expect(mockEsClient.inference.inference).toHaveBeenCalledWith( + expect(mockEsClient.transport.request).toHaveBeenCalledWith( { - inference_id: '', - input: 'Hello world', - task_type: 'completion', + body: { messages: [{ content: 'Hello world', role: 'user' }], n: undefined }, + method: 'POST', + path: '_inference/completion/test/_unified', }, - { asStream: true, signal } + { asStream: true } ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore - mockEsClient.inference.inference = mockError; + mockEsClient.transport.request = mockError; await expect( - connector.performApiCompletionStream({ input: 'What is Elastic?' }) + connector.performApiUnifiedCompletionStream({ + body: { messages: [{ content: 'What is Elastic?', role: 'user' }] }, + }) ).rejects.toThrow('API Error'); }); it('responds with a readable stream', async () => { - const response = await connector.performApiCompletionStream({ - input: 'What is Elastic?', + const stream = Readable.from([ + `data: {"id":"chatcmpl-AbLKRuRMZCAcMMQdl96KMTUgAfZNg","choices":[{"delta":{"content":" you"},"index":0}],"model":"gpt-4o-2024-08-06","object":"chat.completion.chunk"}\n\n`, + `data: [DONE]\n\n`, + ]); + mockEsClient.transport.request.mockResolvedValue(stream); + const response = await connector.performApiUnifiedCompletionStream({ + body: { messages: [{ content: 'What is Elastic?', role: 'user' }] }, }); - expect(response instanceof PassThrough).toEqual(true); + expect(response instanceof Readable).toEqual(true); }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/inference/inference.ts b/x-pack/plugins/stack_connectors/server/connector_types/inference/inference.ts index d9aa4bf044e1d..d6c9af0e1365e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/inference/inference.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/inference/inference.ts @@ -6,36 +6,44 @@ */ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; - -import { PassThrough, Stream } from 'stream'; -import { IncomingMessage } from 'http'; +import { Stream } from 'openai/streaming'; +import { Readable } from 'stream'; import { AxiosError } from 'axios'; import { InferenceInferenceRequest, InferenceInferenceResponse, - InferenceTaskType, } from '@elastic/elasticsearch/lib/api/types'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/usage'; +import { filter, from, identity, map, mergeMap, Observable, tap } from 'rxjs'; +import OpenAI from 'openai'; +import { ChatCompletionChunk } from 'openai/resources'; import { ChatCompleteParamsSchema, RerankParamsSchema, SparseEmbeddingParamsSchema, TextEmbeddingParamsSchema, + UnifiedChatCompleteParamsSchema, } from '../../../common/inference/schema'; import { Config, Secrets, - ChatCompleteParams, - ChatCompleteResponse, - StreamingResponse, RerankParams, RerankResponse, SparseEmbeddingParams, SparseEmbeddingResponse, TextEmbeddingParams, TextEmbeddingResponse, + UnifiedChatCompleteParams, + UnifiedChatCompleteResponse, + DashboardActionParams, + DashboardActionResponse, + ChatCompleteParams, + ChatCompleteResponse, } from '../../../common/inference/types'; import { SUB_ACTION } from '../../../common/inference/constants'; +import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; +import { chunksIntoMessage, eventSourceStreamIntoObservable } from './helpers'; export class InferenceConnector extends SubActionConnector { // Not using Axios @@ -60,10 +68,25 @@ export class InferenceConnector extends SubActionConnector { } private registerSubActions() { + // non-streaming unified completion task this.registerSubAction({ - name: SUB_ACTION.COMPLETION, - method: 'performApiCompletion', - schema: ChatCompleteParamsSchema, + name: SUB_ACTION.UNIFIED_COMPLETION, + method: 'performApiUnifiedCompletion', + schema: UnifiedChatCompleteParamsSchema, + }); + + // streaming unified completion task + this.registerSubAction({ + name: SUB_ACTION.UNIFIED_COMPLETION_STREAM, + method: 'performApiUnifiedCompletionStream', + schema: UnifiedChatCompleteParamsSchema, + }); + + // streaming unified completion task for langchain + this.registerSubAction({ + name: SUB_ACTION.UNIFIED_COMPLETION_ASYNC_ITERATOR, + method: 'performApiUnifiedCompletionAsyncIterator', + schema: UnifiedChatCompleteParamsSchema, }); this.registerSubAction({ @@ -85,8 +108,8 @@ export class InferenceConnector extends SubActionConnector { }); this.registerSubAction({ - name: SUB_ACTION.COMPLETION_STREAM, - method: 'performApiCompletionStream', + name: SUB_ACTION.COMPLETION, + method: 'performApiCompletion', schema: ChatCompleteParamsSchema, }); } @@ -96,16 +119,112 @@ export class InferenceConnector extends SubActionConnector { * @param input the text on which you want to perform the inference task. * @signal abort signal */ - public async performApiCompletion({ - input, - signal, - }: ChatCompleteParams & { signal?: AbortSignal }): Promise { - const response = await this.performInferenceApi( - { inference_id: this.inferenceId, input, task_type: 'completion' }, - false, - signal + public async performApiUnifiedCompletion( + params: UnifiedChatCompleteParams + ): Promise { + const res = await this.performApiUnifiedCompletionStream(params); + + const obs$ = from(eventSourceStreamIntoObservable(res as unknown as Readable)).pipe( + filter((line) => !!line && line !== '[DONE]'), + map((line) => { + return JSON.parse(line) as OpenAI.ChatCompletionChunk | { error: { message: string } }; + }), + tap((line) => { + if ('error' in line) { + throw new Error(line.error.message); + } + if ( + 'choices' in line && + line.choices.length && + line.choices[0].finish_reason === 'length' + ) { + throw new Error('createTokenLimitReachedError()'); + } + }), + filter((line): line is OpenAI.ChatCompletionChunk => { + return 'object' in line && line.object === 'chat.completion.chunk'; + }), + mergeMap((chunk): Observable => { + const events: UnifiedChatCompleteResponse[] = []; + events.push({ + choices: chunk.choices.map((c) => ({ + message: { + tool_calls: c.delta.tool_calls?.map((t) => ({ + index: t.index, + id: t.id, + function: t.function, + type: t.type, + })), + content: c.delta.content, + refusal: c.delta.refusal, + role: c.delta.role, + }, + finish_reason: c.finish_reason, + index: c.index, + })), + id: chunk.id, + model: chunk.model, + object: chunk.object, + usage: chunk.usage, + }); + return from(events); + }), + identity + ); + + return chunksIntoMessage(obs$); + } + + /** + * responsible for making a esClient inference method to perform chat completetion task endpoint and returning the service response data + * @param input the text on which you want to perform the inference task. + * @signal abort signal + */ + public async performApiUnifiedCompletionStream(params: UnifiedChatCompleteParams) { + return await this.esClient.transport.request( + { + method: 'POST', + path: `_inference/completion/${this.inferenceId}/_unified`, + body: { ...params.body, n: undefined }, // exclude n param for now, constant is used on the inference API side + }, + { + asStream: true, + } ); - return response.completion!; + } + + /** + * Streamed requests (langchain) + * @param params - the request body + * @returns { + * consumerStream: Stream; the result to be read/transformed on the server and sent to the client via Server Sent Events + * tokenCountStream: Stream; the result for token counting stream + * } + */ + public async performApiUnifiedCompletionAsyncIterator( + params: UnifiedChatCompleteParams & { signal?: AbortSignal }, + connectorUsageCollector: ConnectorUsageCollector + ): Promise<{ + consumerStream: Stream; + tokenCountStream: Stream; + }> { + try { + connectorUsageCollector.addRequestBodyBytes(undefined, params.body); + const res = await this.performApiUnifiedCompletionStream(params); + const controller = new AbortController(); + // splits the stream in two, one is used for the UI and other for token tracking + + const stream = Stream.fromSSEResponse( + { body: res } as unknown as Response, + controller + ); + const teed = stream.tee(); + return { consumerStream: teed[0], tokenCountStream: teed[1] }; + // since we do not use the sub action connector request method, we need to do our own error handling + } catch (e) { + const errorMessage = this.getResponseErrorMessage(e); + throw new Error(errorMessage); + } } /** @@ -198,35 +317,56 @@ export class InferenceConnector extends SubActionConnector { } } - private async streamAPI({ + /** + * responsible for making a esClient inference method to perform chat completetion task endpoint and returning the service response data + * @param input the text on which you want to perform the inference task. + * @signal abort signal + */ + public async performApiCompletion({ input, signal, - }: ChatCompleteParams & { signal?: AbortSignal }): Promise { + }: ChatCompleteParams & { signal?: AbortSignal }): Promise { const response = await this.performInferenceApi( - { inference_id: this.inferenceId, input, task_type: this.taskType as InferenceTaskType }, - true, + { inference_id: this.inferenceId, input, task_type: 'completion' }, + false, signal ); - - return (response as unknown as Stream).pipe(new PassThrough()); + return response.completion!; } /** - * takes input. It calls the streamApi method to make a - * request to the Inference API with the message. It then returns a Transform stream - * that pipes the response from the API through the transformToString function, - * which parses the proprietary response into a string of the response text alone - * @param input A message to be sent to the API - * @signal abort signal + * retrieves a dashboard from the Kibana server and checks if the + * user has the necessary privileges to access it. + * @param dashboardId The ID of the dashboard to retrieve. */ - public async performApiCompletionStream({ - input, - signal, - }: ChatCompleteParams & { signal?: AbortSignal }): Promise { - const res = (await this.streamAPI({ - input, - signal, - })) as unknown as IncomingMessage; - return res; + public async getDashboard({ + dashboardId, + }: DashboardActionParams): Promise { + const privilege = (await this.esClient.transport.request({ + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + index: [ + { + names: ['.kibana-event-log-*'], + allow_restricted_indices: true, + privileges: ['read'], + }, + ], + }, + })) as { has_all_requested: boolean }; + + if (!privilege?.has_all_requested) { + return { available: false }; + } + + const response = await initDashboard({ + logger: this.logger, + savedObjectsClient: this.savedObjectsClient, + dashboardId, + genAIProvider: 'Inference', + }); + + return { available: response.success }; } } diff --git a/x-pack/plugins/task_manager/server/saved_objects/model_versions/task_model_versions.ts b/x-pack/plugins/task_manager/server/saved_objects/model_versions/task_model_versions.ts index 775b3ea2f8cad..a86aed7e358fe 100644 --- a/x-pack/plugins/task_manager/server/saved_objects/model_versions/task_model_versions.ts +++ b/x-pack/plugins/task_manager/server/saved_objects/model_versions/task_model_versions.ts @@ -8,6 +8,10 @@ import { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; import { taskSchemaV1, taskSchemaV2 } from '../schemas/task'; +// IMPORTANT!!! +// When adding new model versions, make sure to manually test +// downgrading to the previous version. This is a gap in our +// automated test coverage so manual testing is needed. export const taskModelVersions: SavedObjectsModelVersionMap = { '1': { changes: [ diff --git a/x-pack/plugins/task_manager/server/saved_objects/schemas/task.test.ts b/x-pack/plugins/task_manager/server/saved_objects/schemas/task.test.ts new file mode 100644 index 0000000000000..709e50bc54bf9 --- /dev/null +++ b/x-pack/plugins/task_manager/server/saved_objects/schemas/task.test.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { validateDuration } from './task'; + +test('allows valid duration', () => { + expect(validateDuration('1s')).toBeUndefined(); + expect(validateDuration('45346s')).toBeUndefined(); + expect(validateDuration('10m')).toBeUndefined(); + expect(validateDuration('30000000h')).toBeUndefined(); + expect(validateDuration('3245d')).toBeUndefined(); +}); + +test('returns error message for invalid duration', () => { + expect(validateDuration('10x')).toBe('string is not a valid duration: 10x'); + expect(validateDuration('PT1M')).toBe('string is not a valid duration: PT1M'); + expect(validateDuration('foo')).toBe('string is not a valid duration: foo'); + expect(validateDuration('1 minute')).toBe('string is not a valid duration: 1 minute'); + expect(validateDuration('1hr')).toBe('string is not a valid duration: 1hr'); +}); diff --git a/x-pack/plugins/task_manager/server/saved_objects/schemas/task.ts b/x-pack/plugins/task_manager/server/saved_objects/schemas/task.ts index 2a6ee5c92198c..25b6a1cb079d0 100644 --- a/x-pack/plugins/task_manager/server/saved_objects/schemas/task.ts +++ b/x-pack/plugins/task_manager/server/saved_objects/schemas/task.ts @@ -6,6 +6,13 @@ */ import { schema } from '@kbn/config-schema'; +import { isInterval } from '../../lib/intervals'; + +export function validateDuration(duration: string) { + if (!isInterval(duration)) { + return 'string is not a valid duration: ' + duration; + } +} export const taskSchemaV1 = schema.object({ taskType: schema.string(), @@ -15,7 +22,7 @@ export const taskSchemaV1 = schema.object({ runAt: schema.string(), schedule: schema.maybe( schema.object({ - interval: schema.duration(), + interval: schema.string({ validate: validateDuration }), }) ), params: schema.string(), diff --git a/x-pack/solutions/observability/plugins/observability/public/components/rule_condition_chart/helpers.ts b/x-pack/solutions/observability/plugins/observability/public/components/rule_condition_chart/helpers.ts index 30663d02cda72..775da2fc1c805 100644 --- a/x-pack/solutions/observability/plugins/observability/public/components/rule_condition_chart/helpers.ts +++ b/x-pack/solutions/observability/plugins/observability/public/components/rule_condition_chart/helpers.ts @@ -18,7 +18,7 @@ export const getLensOperationFromRuleMetric = (metric: GenericMetric): LensOpera const { aggType, field, filter = '' } = metric; let operation: string = aggType; const operationArgs: string[] = []; - const escapedFilter = filter.replace(/'/g, "\\'"); + const escapedFilter = filter.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); if (aggType === Aggregators.RATE) { return { diff --git a/x-pack/solutions/observability/plugins/observability/server/ui_settings.ts b/x-pack/solutions/observability/plugins/observability/server/ui_settings.ts index e5695a3c9034d..a68ae28b267fc 100644 --- a/x-pack/solutions/observability/plugins/observability/server/ui_settings.ts +++ b/x-pack/solutions/observability/plugins/observability/server/ui_settings.ts @@ -325,7 +325,7 @@ export const uiSettings: Record = { }, }), schema: schema.boolean(), - value: true, + value: false, requiresPageReload: true, type: 'boolean', }, diff --git a/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/components/graph_investigation/graph_investigation.tsx b/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/components/graph_investigation/graph_investigation.tsx index 081b4ec28c6a5..bd57082ba4cb9 100644 --- a/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/components/graph_investigation/graph_investigation.tsx +++ b/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/components/graph_investigation/graph_investigation.tsx @@ -126,21 +126,46 @@ const useGraphPopovers = ( }; interface GraphInvestigationProps { - dataView: DataView; - eventIds: string[]; - timestamp: string | null; + /** + * The initial state to use for the graph investigation view. + */ + initialState: { + /** + * The data view to use for the graph investigation view. + */ + dataView: DataView; + + /** + * The origin events for the graph investigation view. + */ + originEventIds: Array<{ + /** + * The ID of the origin event. + */ + id: string; + + /** + * A flag indicating whether the origin event is an alert or not. + */ + isAlert: boolean; + }>; + + /** + * The initial timerange for the graph investigation view. + */ + timeRange: TimeRange; + }; } /** * Graph investigation view allows the user to expand nodes and view related entities. */ export const GraphInvestigation: React.FC = memo( - ({ dataView, eventIds, timestamp = new Date().toISOString() }: GraphInvestigationProps) => { + ({ + initialState: { dataView, originEventIds, timeRange: initialTimeRange }, + }: GraphInvestigationProps) => { const [searchFilters, setSearchFilters] = useState(() => []); - const [timeRange, setTimeRange] = useState({ - from: `${timestamp}||-30m`, - to: `${timestamp}||+30m`, - }); + const [timeRange, setTimeRange] = useState(initialTimeRange); const { services: { uiSettings }, @@ -153,7 +178,7 @@ export const GraphInvestigation: React.FC = memo( [...searchFilters], getEsQueryConfig(uiSettings as Parameters[0]) ), - [searchFilters, dataView, uiSettings] + [dataView, searchFilters, uiSettings] ); const { nodeExpandPopover, openPopoverCallback } = useGraphPopovers( @@ -166,7 +191,7 @@ export const GraphInvestigation: React.FC = memo( const { data, refresh, isFetching } = useFetchGraphData({ req: { query: { - eventIds, + originEventIds, esQuery: query, start: timeRange.from, end: timeRange.to, diff --git a/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/hooks/use_fetch_graph_data.test.tsx b/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/hooks/use_fetch_graph_data.test.tsx index e494ff0957ecb..da5eaee9bfbf9 100644 --- a/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/hooks/use_fetch_graph_data.test.tsx +++ b/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/hooks/use_fetch_graph_data.test.tsx @@ -33,7 +33,7 @@ describe('useFetchGraphData', () => { return useFetchGraphData({ req: { query: { - eventIds: [], + originEventIds: [], start: '2021-09-01T00:00:00.000Z', end: '2021-09-01T23:59:59.999Z', }, @@ -52,7 +52,7 @@ describe('useFetchGraphData', () => { return useFetchGraphData({ req: { query: { - eventIds: [], + originEventIds: [], start: '2021-09-01T00:00:00.000Z', end: '2021-09-01T23:59:59.999Z', }, @@ -75,7 +75,7 @@ describe('useFetchGraphData', () => { return useFetchGraphData({ req: { query: { - eventIds: [], + originEventIds: [], start: '2021-09-01T00:00:00.000Z', end: '2021-09-01T23:59:59.999Z', }, @@ -98,7 +98,7 @@ describe('useFetchGraphData', () => { return useFetchGraphData({ req: { query: { - eventIds: [], + originEventIds: [], start: '2021-09-01T00:00:00.000Z', end: '2021-09-01T23:59:59.999Z', }, diff --git a/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/hooks/use_fetch_graph_data.ts b/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/hooks/use_fetch_graph_data.ts index 74cca4693e801..477492a3bbb7b 100644 --- a/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/hooks/use_fetch_graph_data.ts +++ b/x-pack/solutions/security/packages/kbn-cloud-security-posture/graph/src/hooks/use_fetch_graph_data.ts @@ -81,13 +81,13 @@ export const useFetchGraphData = ({ options, }: UseFetchGraphDataParams): UseFetchGraphDataResult => { const queryClient = useQueryClient(); - const { esQuery, eventIds, start, end } = req.query; + const { esQuery, originEventIds, start, end } = req.query; const { services: { http }, } = useKibana(); const QUERY_KEY = useMemo( - () => ['useFetchGraphData', eventIds, start, end, esQuery], - [end, esQuery, eventIds, start] + () => ['useFetchGraphData', originEventIds, start, end, esQuery], + [end, esQuery, originEventIds, start] ); const { isLoading, isError, data, isFetching } = useQuery( diff --git a/packages/kbn-securitysolution-autocomplete/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/README.md similarity index 100% rename from packages/kbn-securitysolution-autocomplete/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/index.ts new file mode 100644 index 0000000000000..f3768e8cd37f7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/index.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +export * from './src/check_empty_value'; +export * from './src/es_field_selector'; +export * from './src/field_value_exists'; +export * from './src/field_value_lists'; +export * from './src/field_value_match'; +export * from './src/field_value_match_any'; +export * from './src/field_value_wildcard'; +export * from './src/filter_field_to_list'; +export * from './src/get_generic_combo_box_props'; +export * from './src/get_operators'; +export * from './src/hooks'; +export * from './src/operator'; +export * from './src/param_is_valid'; +export * from './src/param_contains_space'; + +export { default as autoCompletei18n } from './src/translations'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/jest.config.js b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/jest.config.js new file mode 100644 index 0000000000000..7384086c58710 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete'], +}; diff --git a/packages/kbn-securitysolution-autocomplete/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-autocomplete/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/package.json new file mode 100644 index 0000000000000..fcce028035c42 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/securitysolution-autocomplete", + "version": "1.0.0", + "description": "Security Solution auto complete", + "license": "Elastic License 2.0", + "private": true, + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/autocomplete/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/autocomplete/index.mock.ts new file mode 100644 index 0000000000000..2372ad727e9f1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/autocomplete/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// Copied from "src/plugins/data/public/mocks.ts" but without any type information +// TODO: Remove this in favor of the data/public/mocks if/when they become available, https://github.com/elastic/kibana/issues/100715 +export const autocompleteStartMock = { + getQuerySuggestions: jest.fn(), + getValueSuggestions: jest.fn(), + hasQuerySuggestions: jest.fn(), +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.test.ts new file mode 100644 index 0000000000000..4f99799bb468e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.test.ts @@ -0,0 +1,48 @@ +/* + * 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 { checkEmptyValue } from '.'; +import { getField } from '../fields/index.mock'; +import * as i18n from '../translations'; + +describe('check_empty_value', () => { + test('returns no errors if no field has been selected', () => { + const isValid = checkEmptyValue('', undefined, true, false); + + expect(isValid).toBeUndefined(); + }); + + test('returns error string if user has touched a required input and left empty', () => { + const isValid = checkEmptyValue(undefined, getField('@timestamp'), true, true); + + expect(isValid).toEqual(i18n.FIELD_REQUIRED_ERR); + }); + + test('returns no errors if required input is empty but user has not yet touched it', () => { + const isValid = checkEmptyValue(undefined, getField('@timestamp'), true, false); + + expect(isValid).toBeUndefined(); + }); + + test('returns no errors if user has touched an input that is not required and left empty', () => { + const isValid = checkEmptyValue(undefined, getField('@timestamp'), false, true); + + expect(isValid).toBeUndefined(); + }); + + test('returns no errors if user has touched an input that is not required and left empty string', () => { + const isValid = checkEmptyValue('', getField('@timestamp'), false, true); + + expect(isValid).toBeUndefined(); + }); + + test('returns null if input value is not empty string or undefined', () => { + const isValid = checkEmptyValue('hellooo', getField('@timestamp'), false, true); + + expect(isValid).toBeNull(); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.ts new file mode 100644 index 0000000000000..285c91842f2fe --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/check_empty_value/index.ts @@ -0,0 +1,33 @@ +/* + * 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 { DataViewFieldBase } from '@kbn/es-query'; +import * as i18n from '../translations'; + +/** + * Determines if empty value is ok + */ +export const checkEmptyValue = ( + param: string | undefined, + field: DataViewFieldBase | undefined, + isRequired: boolean, + touched: boolean +): string | undefined | null => { + if (isRequired && touched && (param == null || param.trim() === '')) { + return i18n.FIELD_REQUIRED_ERR; + } + + if ( + field == null || + (isRequired && !touched) || + (!isRequired && (param == null || param === '')) + ) { + return undefined; + } + + return null; +}; diff --git a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/__snapshots__/index.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/__snapshots__/index.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/__snapshots__/index.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/__snapshots__/index.test.tsx.snap diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/disabled_types_with_tooltip_text.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/disabled_types_with_tooltip_text.test.ts new file mode 100644 index 0000000000000..743ba33fbbe53 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/disabled_types_with_tooltip_text.test.ts @@ -0,0 +1,18 @@ +/* + * 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 { disabledTypesWithTooltipText } from '../disabled_types_with_tooltip_text'; + +jest.mock('../../translations', () => ({ + BINARY_TYPE_NOT_SUPPORTED: 'Binary fields are currently unsupported', +})); +describe('disabledTypesWithTooltipText', () => { + it('should return Binary fields are currently unsupported for binary type', () => { + const type = 'binary'; + expect(disabledTypesWithTooltipText[type]).toEqual('Binary fields are currently unsupported'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/index.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/index.test.tsx new file mode 100644 index 0000000000000..10db3fcce5f52 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/index.test.tsx @@ -0,0 +1,142 @@ +/* + * 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 React from 'react'; +import { fireEvent, render, waitFor, within } from '@testing-library/react'; +import '@testing-library/jest-dom'; + +import { EsFieldSelector } from '..'; +import { fields, getField } from '../../fields/index.mock'; + +describe('FieldComponent', () => { + it('should render the component enabled and displays the selected field correctly', () => { + const wrapper = render( + + ); + expect(wrapper.container).toMatchSnapshot(); + const comboBox = wrapper.getByTestId('fieldAutocompleteComboBox'); + const input = within(comboBox).getByRole('combobox'); + expect(input).toHaveAttribute('value', 'machine.os.raw'); + }); + it('should render the component disabled if isDisabled is true', () => { + const wrapper = render( + + ); + expect(wrapper.container).toMatchSnapshot(); + expect(wrapper.getByTestId('fieldAutocompleteComboBox').querySelector('input')).toBeDisabled(); + }); + it('should render the loading spinner if isLoading is true when clicked', () => { + const wrapper = render( + + ); + const fieldAutocompleteComboBox = wrapper.getByTestId('fieldAutocompleteComboBox'); + expect(wrapper.container).toMatchSnapshot(); + fireEvent.click(fieldAutocompleteComboBox); + expect(wrapper.getByRole('progressbar')).toBeInTheDocument(); + }); + it('should allow user to clear values if isClearable is true', () => { + const wrapper = render( + + ); + expect(wrapper.container).toMatchSnapshot(); + expect(wrapper.getByTestId('comboBoxClearButton')).toBeInTheDocument(); + }); + it('should change the selected value', async () => { + const wrapper = render( + + ); + const fieldAutocompleteComboBox = wrapper.getByTestId('comboBoxSearchInput'); + fireEvent.change(fieldAutocompleteComboBox, { target: { value: '_source' } }); + expect(fieldAutocompleteComboBox).toHaveValue('_source'); + }); + + it('it allows custom user input if "acceptsCustomOptions" is "true"', async () => { + const mockOnChange = jest.fn(); + const wrapper = render( + + ); + + const fieldAutocompleteComboBox = wrapper.getByTestId('comboBoxSearchInput'); + fireEvent.change(fieldAutocompleteComboBox, { target: { value: 'custom' } }); + await waitFor(() => + expect(wrapper.getByTestId('fieldAutocompleteComboBox')).toHaveTextContent('custom') + ); + }); +}); diff --git a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/use_es_field.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/use_es_field.test.ts similarity index 97% rename from packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/use_es_field.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/use_es_field.test.ts index 942ccbc29c38e..1fb07e21fc915 100644 --- a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/use_es_field.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/use_es_field.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { DataViewFieldBase } from '@kbn/es-query'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/disabled_types_with_tooltip_text.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/disabled_types_with_tooltip_text.ts new file mode 100644 index 0000000000000..5b24ecb736054 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/disabled_types_with_tooltip_text.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +interface DisabledTypesTextType { + [typeName: string]: string; +} +import * as i18n from '../translations'; + +export const disabledTypesWithTooltipText: DisabledTypesTextType = { + binary: i18n.BINARY_TYPE_NOT_SUPPORTED, +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/index.tsx new file mode 100644 index 0000000000000..8ce7e7ed5507d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/index.tsx @@ -0,0 +1,107 @@ +/* + * 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 React from 'react'; +import { EuiComboBox } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { FieldBaseProps } from './types'; +import { useEsField } from './use_es_field'; + +const AS_PLAIN_TEXT = { asPlainText: true }; + +interface EsFieldSelectorProps extends FieldBaseProps { + isClearable?: boolean; + isDisabled?: boolean; + isLoading?: boolean; + placeholder: string; + acceptsCustomOptions?: boolean; + showMappingConflicts?: boolean; + 'aria-label'?: string; +} + +export function EsFieldSelector({ + fieldInputWidth, + fieldTypeFilter = [], + indexPattern, + isClearable = false, + isDisabled = false, + isLoading = false, + isRequired = false, + onChange, + placeholder, + selectedField, + acceptsCustomOptions = false, + showMappingConflicts = false, + 'aria-label': ariaLabel, +}: EsFieldSelectorProps): JSX.Element { + const { + isInvalid, + comboOptions, + selectedComboOptions, + fieldWidth, + renderFields, + handleTouch, + handleValuesChange, + handleCreateCustomOption, + } = useEsField({ + indexPattern, + fieldTypeFilter, + isRequired, + selectedField, + fieldInputWidth, + showMappingConflicts, + onChange, + }); + + if (acceptsCustomOptions) { + return ( + + ); + } + + return ( + + ); +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/types.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/types.ts new file mode 100644 index 0000000000000..e300df89e1c3c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/types.ts @@ -0,0 +1,34 @@ +/* + * 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 { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; +import { FieldConflictsInfo } from '@kbn/securitysolution-list-utils'; +import { GetGenericComboBoxPropsReturn } from '../get_generic_combo_box_props'; + +export interface FieldBaseProps { + indexPattern: DataViewBase | undefined; + fieldTypeFilter?: string[]; + isRequired?: boolean; + selectedField?: DataViewFieldBase | undefined; + fieldInputWidth?: number; + showMappingConflicts?: boolean; + onChange: (a: DataViewFieldBase[]) => void; +} + +export interface ComboBoxFields { + availableFields: DataViewField[]; + selectedFields: DataViewField[]; +} + +export interface GetFieldComboBoxPropsReturn extends GetGenericComboBoxPropsReturn { + disabledLabelTooltipTexts: { [label: string]: string }; + mappingConflictsTooltipInfo: { [label: string]: FieldConflictsInfo[] }; +} + +export interface DataViewField extends DataViewFieldBase { + esTypes?: string[]; +} diff --git a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/use_es_field.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/use_es_field.tsx similarity index 94% rename from packages/kbn-securitysolution-autocomplete/src/es_field_selector/use_es_field.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/use_es_field.tsx index 615571d989607..1d6b84618af3e 100644 --- a/packages/kbn-securitysolution-autocomplete/src/es_field_selector/use_es_field.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/es_field_selector/use_es_field.tsx @@ -1,14 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; -import { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { EuiComboBoxOptionOption, EuiIcon, diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.test.tsx new file mode 100644 index 0000000000000..9fc10f6ba3bc1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.test.tsx @@ -0,0 +1,23 @@ +/* + * 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 React from 'react'; +import { mount } from 'enzyme'; + +import { AutocompleteFieldExistsComponent } from '.'; + +describe('AutocompleteFieldExistsComponent', () => { + test('it renders field disabled', () => { + const wrapper = mount(); + + expect( + wrapper + .find(`[data-test-subj="valuesAutocompleteComboBox existsComboxBox"] input`) + .prop('disabled') + ).toBeTruthy(); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.tsx new file mode 100644 index 0000000000000..ccd27f559e124 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_exists/index.tsx @@ -0,0 +1,38 @@ +/* + * 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 React from 'react'; +import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui'; + +const NO_OPTIONS_FOR_EXIST: EuiComboBoxOptionOption[] = []; + +interface AutocompleteFieldExistsProps { + placeholder: string; + rowLabel?: string; + 'aria-label'?: string; +} + +export const AutocompleteFieldExistsComponent: React.FC = ({ + placeholder, + rowLabel, + 'aria-label': ariaLabel, +}): JSX.Element => ( + + + +); + +AutocompleteFieldExistsComponent.displayName = 'AutocompleteFieldExists'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx new file mode 100644 index 0000000000000..30323eba26855 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx @@ -0,0 +1,268 @@ +/* + * 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 React from 'react'; +import { mount } from 'enzyme'; +import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; +import { waitFor } from '@testing-library/react'; +import type { ListSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { getField } from '../fields/index.mock'; +import { AutocompleteFieldListsComponent } from '.'; +import { + getListResponseMock, + getFoundListsBySizeSchemaMock, + DATE_NOW, + IMMUTABLE, + VERSION, +} from '../list_schema/index.mock'; + +// TODO: Once these mocks are available, use them instead of hand mocking, https://github.com/elastic/kibana/issues/100715 +// const mockKibanaHttpService = coreMock.createStart().http; +// import { coreMock } from '../../../../../../../../../../src/core/public/mocks'; +const mockKibanaHttpService = jest.fn(); +const mockShowValueListModal = jest.fn(); +const MockedShowValueListModal = (props: unknown) => { + mockShowValueListModal(props); + return <>; +}; +const mockStart = jest.fn(); +const mockKeywordList: ListSchema = { + ...getListResponseMock(), + id: 'keyword_list', + name: 'keyword list', + type: 'keyword', +}; +const mockResult = { ...getFoundListsBySizeSchemaMock() }; +mockResult.smallLists = [...mockResult.smallLists, mockKeywordList]; +mockResult.largeLists = []; +jest.mock('@kbn/securitysolution-list-hooks', () => { + const originalModule = jest.requireActual('@kbn/securitysolution-list-hooks'); + + return { + ...originalModule, + useFindListsBySize: () => ({ + error: undefined, + loading: false, + result: mockResult, + start: mockStart.mockReturnValue(mockResult), + }), + }; +}); + +describe('AutocompleteFieldListsComponent', () => { + test('it renders disabled if "isDisabled" is true', async () => { + const wrapper = mount( + + ); + + expect( + wrapper + .find(`[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] input`) + .prop('disabled') + ).toBeTruthy(); + }); + + test('it renders loading if "isLoading" is true', async () => { + const wrapper = mount( + + ); + + wrapper + .find(`[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] button`) + .at(0) + .simulate('click'); + expect( + wrapper + .find( + `EuiComboBoxOptionsList[data-test-subj="valuesAutocompleteComboBox listsComboxBox-optionsList"]` + ) + .prop('isLoading') + ).toBeTruthy(); + }); + + test('it allows user to clear values if "isClearable" is true', async () => { + const wrapper = mount( + + ); + expect( + wrapper + .find('EuiComboBox[data-test-subj="valuesAutocompleteComboBox listsComboxBox"]') + .prop('options') + ).toEqual([{ label: 'some name', disabled: false }]); + }); + + test('it correctly displays lists that match the selected "keyword" field esType', () => { + const wrapper = mount( + + ); + + wrapper.find('[data-test-subj="comboBoxToggleListButton"] button').simulate('click'); + + expect( + wrapper + .find('EuiComboBox[data-test-subj="valuesAutocompleteComboBox listsComboxBox"]') + .prop('options') + ).toEqual([{ label: 'keyword list', disabled: false }]); + }); + + test('it correctly displays lists that match the selected "ip" field esType', () => { + const wrapper = mount( + + ); + + wrapper.find('[data-test-subj="comboBoxToggleListButton"] button').simulate('click'); + + expect( + wrapper + .find('EuiComboBox[data-test-subj="valuesAutocompleteComboBox listsComboxBox"]') + .prop('options') + ).toEqual([{ label: 'some name', disabled: false }]); + }); + + test('it correctly displays selected list', async () => { + const wrapper = mount( + + ); + + expect( + wrapper + .find(`[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] input`) + .at(0) + .props().value + ).toEqual('some name'); + }); + + test('it invokes "onChange" when option selected', async () => { + const mockOnChange = jest.fn(); + const wrapper = mount( + + ); + + ( + wrapper.find(EuiComboBox).props() as unknown as { + onChange: (a: EuiComboBoxOptionOption[]) => void; + } + ).onChange([{ label: 'some name', disabled: false }]); + + await waitFor(() => { + expect(mockOnChange).toHaveBeenCalledWith({ + '@timestamp': DATE_NOW, + _version: undefined, + created_at: DATE_NOW, + created_by: 'some user', + description: 'some description', + deserializer: undefined, + id: 'some-list-id', + immutable: IMMUTABLE, + meta: {}, + name: 'some name', + serializer: undefined, + tie_breaker_id: '6a76b69d-80df-4ab2-8c3e-85f466b06a0e', + type: 'ip', + updated_at: DATE_NOW, + updated_by: 'some user', + version: VERSION, + }); + }); + }); + + test('it render the value list modal', async () => { + mockShowValueListModal.mockReset(); + mount( + + ); + + expect(mockShowValueListModal).toHaveBeenCalledWith( + expect.objectContaining({ + children: 'Show value list', + listId: 'some-list-id', + shouldShowContentIfModalNotAvailable: false, + }) + ); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.tsx new file mode 100644 index 0000000000000..480791b001c5f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.tsx @@ -0,0 +1,182 @@ +/* + * 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 React, { ElementType, useCallback, useEffect, useMemo, useState } from 'react'; +import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow, EuiLink, EuiText } from '@elastic/eui'; +import type { ListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { useFindListsBySize } from '@kbn/securitysolution-list-hooks'; +import { DataViewFieldBase } from '@kbn/es-query'; +import { getDocLinks } from '@kbn/doc-links'; + +import { filterFieldToList } from '../filter_field_to_list'; +import { getGenericComboBoxProps } from '../get_generic_combo_box_props'; + +// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 +// import { HttpStart } from '@kbn/core/public'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type HttpStart = any; + +import * as i18n from '../translations'; + +const SINGLE_SELECTION = { asPlainText: true }; + +interface AutocompleteFieldListsProps { + httpService: HttpStart; + isClearable: boolean; + isDisabled: boolean; + isLoading: boolean; + onChange: (arg: ListSchema) => void; + placeholder: string; + rowLabel?: string; + selectedField: DataViewFieldBase | undefined; + selectedValue: string | undefined; + allowLargeValueLists?: boolean; + 'aria-label'?: string; + showValueListModal: ElementType; +} + +export interface AutocompleteListsData { + smallLists: ListSchema[]; + largeLists: ListSchema[]; +} + +export const AutocompleteFieldListsComponent: React.FC = ({ + httpService, + isClearable = false, + isDisabled = false, + isLoading = false, + onChange, + placeholder, + rowLabel, + selectedField, + selectedValue, + allowLargeValueLists = false, + 'aria-label': ariaLabel, + showValueListModal, +}): JSX.Element => { + const [error, setError] = useState(undefined); + const [listData, setListData] = useState({ + smallLists: [], + largeLists: [], + }); + const { loading, result, start } = useFindListsBySize(); + const getLabel = useCallback(({ name }: ListSchema) => name, []); + + const optionsMemo = useMemo( + () => filterFieldToList(listData, selectedField), + [listData, selectedField] + ); + const selectedOptionsMemo = useMemo(() => { + if (selectedValue != null) { + const combinedLists = [...listData.smallLists, ...listData.largeLists]; + const list = combinedLists.filter(({ id }) => id === selectedValue); + return list ?? []; + } else { + return []; + } + }, [selectedValue, listData]); + const { comboOptions, labels, selectedComboOptions } = useMemo( + () => + getGenericComboBoxProps({ + getLabel, + options: [...optionsMemo.smallLists, ...optionsMemo.largeLists], + selectedOptions: selectedOptionsMemo, + disabledOptions: allowLargeValueLists ? undefined : optionsMemo.largeLists, // Disable large lists if the rule type doesn't allow it + }), + [optionsMemo, selectedOptionsMemo, getLabel, allowLargeValueLists] + ); + + const handleValuesChange = useCallback( + (newOptions: EuiComboBoxOptionOption[]) => { + const combinedLists = [...optionsMemo.smallLists, ...optionsMemo.largeLists]; + const [newValue] = newOptions.map(({ label }) => combinedLists[labels.indexOf(label)]); + onChange(newValue ?? ''); + }, + [labels, optionsMemo, onChange] + ); + + const setIsTouchedValue = useCallback((): void => { + setError(selectedValue == null ? i18n.FIELD_REQUIRED_ERR : undefined); + }, [selectedValue]); + + useEffect(() => { + if (result != null) { + setListData(result); + } + }, [result]); + + useEffect(() => { + if (selectedField != null && httpService != null) { + start({ + http: httpService, + pageIndex: 1, + pageSize: 500, + }); + } + }, [selectedField, start, httpService]); + + const isLoadingState = useMemo((): boolean => isLoading || loading, [isLoading, loading]); + const ShowValueListModal = showValueListModal; + + const helpText = useMemo(() => { + return ( + <> + {selectedValue && ( + + {i18n.SHOW_VALUE_LIST_MODAL} + + )} + {!allowLargeValueLists && ( + + {i18n.LISTS_TOOLTIP_INFO}{' '} + + {i18n.SEE_DOCUMENTATION} + + + )} + + ); + }, [allowLargeValueLists, selectedValue, ShowValueListModal]); + return ( + + + + ); +}; + +AutocompleteFieldListsComponent.displayName = 'AutocompleteFieldList'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx new file mode 100644 index 0000000000000..8ca17a78764cc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx @@ -0,0 +1,629 @@ +/* + * 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 React from 'react'; +import { ReactWrapper, mount } from 'enzyme'; +import { + EuiComboBox, + EuiComboBoxOptionOption, + EuiFormHelpText, + EuiSuperSelect, +} from '@elastic/eui'; +import { act, waitFor } from '@testing-library/react'; +import { AutocompleteFieldMatchComponent } from '.'; +import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; +import { fields, getField } from '../fields/index.mock'; +import { autocompleteStartMock } from '../autocomplete/index.mock'; + +jest.mock('../hooks/use_field_value_autocomplete'); +jest.mock('../translations', () => ({ + FIELD_SPACE_WARNING: 'Warning: there is a space', +})); +describe('AutocompleteFieldMatchComponent', () => { + let wrapper: ReactWrapper; + + const getValueSuggestionsMock = jest + .fn() + .mockResolvedValue([false, true, ['value 3', 'value 4'], jest.fn()]); + + const findEuiComboBox = () => + wrapper.find(EuiComboBox).props() as unknown as { + onChange: (a: EuiComboBoxOptionOption[]) => void; + onSearchChange: (a: string) => void; + onCreateOption: (a: string) => void; + }; + + beforeEach(() => { + (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ + false, + true, + ['value 1', 'value 2'], + getValueSuggestionsMock, + ]); + }); + + afterEach(() => { + jest.clearAllMocks(); + wrapper.unmount(); + }); + + test('it renders row label if one passed in', () => { + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatchLabel"] label').at(0).text() + ).toEqual('Row Label'); + }); + + test('it renders disabled if "isDisabled" is true', () => { + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').prop('disabled') + ).toBeTruthy(); + }); + + test('it renders loading if "isLoading" is true', () => { + wrapper = mount( + + ); + wrapper.find('[data-test-subj="valuesAutocompleteMatch"] button').at(0).simulate('click'); + expect( + wrapper + .find('EuiComboBoxOptionsList[data-test-subj="valuesAutocompleteMatch-optionsList"]') + .prop('isLoading') + ).toBeTruthy(); + }); + + test('it allows user to clear values if "isClearable" is true', () => { + wrapper = mount( + + ); + + expect(wrapper.find(`[data-test-subj="comboBoxClearButton"]`)).toBeTruthy(); + }); + + test('it correctly displays selected value', () => { + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').at(0).props().value + ).toEqual('127.0.0.1'); + }); + + test('it invokes "onChange" when new value created', () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + findEuiComboBox().onCreateOption('127.0.0.1'); + + expect(mockOnChange).toHaveBeenCalledWith('127.0.0.1'); + }); + + test('it invokes "onChange" when new value selected', () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + findEuiComboBox().onChange([{ label: 'value 1' }]); + + expect(mockOnChange).toHaveBeenCalledWith('value 1'); + }); + + test('it invokes "onChange" with empty value (i.e. clears selection) when new value searched', () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + act(() => { + findEuiComboBox().onSearchChange('value 12'); + }); + + expect(mockOnChange).toHaveBeenCalledWith(''); + }); + + test('should show the warning helper text if the new value contains spaces when change', async () => { + (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ + false, + true, + [' value 1 ', 'value 2'], + getValueSuggestionsMock, + ]); + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + await waitFor(() => findEuiComboBox().onChange([{ label: ' value 1 ' }])); + wrapper.update(); + expect(mockOnChange).toHaveBeenCalledWith(' value 1 '); + + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeTruthy(); + }); + + test('it refreshes autocomplete with search query when new value searched', () => { + wrapper = mount( + + ); + act(() => { + findEuiComboBox().onSearchChange('value 1'); + }); + + expect(useFieldValueAutocomplete).toHaveBeenCalledWith({ + autocompleteService: autocompleteStartMock, + fieldValue: '', + indexPattern: { + fields, + id: '1234', + title: 'logstash-*', + }, + operatorType: 'match', + query: 'value 1', + selectedField: getField('machine.os.raw'), + }); + }); + + test('it refreshes autocomplete with search query when input field is cleared', () => { + wrapper = mount( + + ); + + act(() => { + findEuiComboBox().onSearchChange('value 1'); + }); + act(() => { + findEuiComboBox().onSearchChange(''); + }); + + // 1st call is initial render, 2nd call sets the search query: + expect(useFieldValueAutocomplete).toHaveBeenNthCalledWith(2, { + autocompleteService: autocompleteStartMock, + fieldValue: 'windows', + indexPattern: { fields, id: '1234', title: 'logstash-*' }, + operatorType: 'match', + query: 'value 1', + selectedField: getField('machine.os.raw'), + }); + // last call is the refresh when input field is cleared + expect(useFieldValueAutocomplete).toHaveBeenLastCalledWith({ + autocompleteService: autocompleteStartMock, + fieldValue: 'windows', + indexPattern: { fields, id: '1234', title: 'logstash-*' }, + operatorType: 'match', + query: '', + selectedField: getField('machine.os.raw'), + }); + }); + + test('should show the warning helper text if the new value contains spaces when searching a new query', () => { + wrapper = mount( + + ); + act(() => { + findEuiComboBox().onSearchChange(' value 1'); + }); + + wrapper.update(); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeTruthy(); + expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); + }); + + test('should show the warning helper text if selectedValue contains spaces when editing', () => { + wrapper = mount( + + ); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeTruthy(); + expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); + }); + + test('should not show the warning helper text if selectedValue is falsy', () => { + wrapper = mount( + + ); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeFalsy(); + }); + + describe('boolean type', () => { + const valueSuggestionsMock = jest.fn().mockResolvedValue([false, false, [], jest.fn()]); + + beforeEach(() => { + (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ + false, + false, + [], + valueSuggestionsMock, + ]); + }); + + test('it displays only two options - "true" or "false"', () => { + wrapper = mount( + + ); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatchBoolean"]').exists() + ).toBeTruthy(); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatchBoolean"]').at(0).prop('options') + ).toEqual([ + { + inputDisplay: 'true', + value: 'true', + }, + { + inputDisplay: 'false', + value: 'false', + }, + ]); + }); + + test('it invokes "onChange" with "true" when selected', () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + ( + wrapper.find(EuiSuperSelect).props() as unknown as { + onChange: (a: string) => void; + } + ).onChange('true'); + + expect(mockOnChange).toHaveBeenCalledWith('true'); + }); + + test('it invokes "onChange" with "false" when selected', () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + ( + wrapper.find(EuiSuperSelect).props() as unknown as { + onChange: (a: string) => void; + } + ).onChange('false'); + + expect(mockOnChange).toHaveBeenCalledWith('false'); + }); + }); + + describe('number type', () => { + const valueSuggestionsMock = jest.fn().mockResolvedValue([false, false, [], jest.fn()]); + + beforeEach(() => { + (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ + false, + false, + [], + valueSuggestionsMock, + ]); + }); + + test('it number input when field type is number', () => { + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="valueAutocompleteFieldMatchNumber"]').exists() + ).toBeTruthy(); + }); + + test('it invokes "onChange" with numeric value when inputted', () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + wrapper + .find('[data-test-subj="valueAutocompleteFieldMatchNumber"] input') + .at(0) + .simulate('change', { target: { value: '8' } }); + + expect(mockOnChange).toHaveBeenCalledWith('8'); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx new file mode 100644 index 0000000000000..a938ad2f7a991 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx @@ -0,0 +1,376 @@ +/* + * 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 React, { useCallback, useMemo, useState, useEffect } from 'react'; +import { + EuiSuperSelect, + EuiFormRow, + EuiFieldNumber, + EuiComboBoxOptionOption, + EuiComboBox, +} from '@elastic/eui'; +import { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; + +import { uniq } from 'lodash'; + +import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; + +// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 +// import { AutocompleteStart } from '../../../../../../../../../../src/plugins/unified_search/public'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AutocompleteStart = any; + +import * as i18n from '../translations'; +import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; +import { + getGenericComboBoxProps, + GetGenericComboBoxPropsReturn, +} from '../get_generic_combo_box_props'; +import { paramIsValid } from '../param_is_valid'; +import { paramContainsSpace } from '../param_contains_space'; + +const BOOLEAN_OPTIONS = [ + { inputDisplay: 'true', value: 'true' }, + { inputDisplay: 'false', value: 'false' }, +]; + +const SINGLE_SELECTION = { asPlainText: true }; + +type Warning = string | React.ReactNode; + +interface AutocompleteFieldMatchProps { + placeholder: string; + selectedField: DataViewFieldBase | undefined; + selectedValue: string | undefined; + indexPattern: DataViewBase | undefined; + isLoading?: boolean; + isDisabled?: boolean; + isClearable?: boolean; + isRequired?: boolean; + fieldInputWidth?: number; + rowLabel?: string; + autocompleteService: AutocompleteStart; + onChange: (arg: string) => void; + onError?: (arg: boolean) => void; + onWarning?: (arg: boolean) => void; + warning?: Warning; + 'aria-label'?: string; +} + +export const AutocompleteFieldMatchComponent: React.FC = ({ + placeholder, + rowLabel, + selectedField, + selectedValue, + indexPattern, + isLoading = false, + isDisabled = false, + isClearable = false, + isRequired = false, + fieldInputWidth, + autocompleteService, + onChange, + onError, + onWarning, + warning, + 'aria-label': ariaLabel, +}): JSX.Element => { + const [searchQuery, setSearchQuery] = useState(''); + const [touched, setIsTouched] = useState(false); + const [error, setError] = useState(undefined); + const [showSpacesWarning, setShowSpacesWarning] = useState(false); + const [isLoadingSuggestions, isSuggestingValues, suggestions] = useFieldValueAutocomplete({ + autocompleteService, + fieldValue: selectedValue, + indexPattern, + operatorType: OperatorTypeEnum.MATCH, + query: searchQuery, + selectedField, + }); + const getLabel = useCallback((option: string): string => option, []); + + const optionsMemo = useMemo((): string[] => { + const valueAsStr = String(selectedValue); + return selectedValue != null && selectedValue.trim() !== '' + ? uniq([valueAsStr, ...suggestions]) + : suggestions; + }, [suggestions, selectedValue]); + + const selectedOptionsMemo = useMemo((): string[] => { + const valueAsStr = String(selectedValue); + return selectedValue ? [valueAsStr] : []; + }, [selectedValue]); + + const handleSpacesWarning = useCallback( + (param: string | undefined) => { + if (!param) return setShowSpacesWarning(false); + setShowSpacesWarning(!!paramContainsSpace(param)); + }, + [setShowSpacesWarning] + ); + + const handleError = useCallback( + (err: string | undefined): void => { + setError((existingErr): string | undefined => { + const oldErr = existingErr != null; + const newErr = err != null; + if (oldErr !== newErr && onError != null) { + onError(newErr); + } + + return err; + }); + }, + [setError, onError] + ); + + const handleWarning = useCallback( + (warn: Warning | undefined): void => { + if (onWarning) { + onWarning(warn !== undefined); + } + }, + [onWarning] + ); + + const { comboOptions, labels, selectedComboOptions } = useMemo( + (): GetGenericComboBoxPropsReturn => + getGenericComboBoxProps({ + getLabel, + options: optionsMemo, + selectedOptions: selectedOptionsMemo, + }), + [optionsMemo, selectedOptionsMemo, getLabel] + ); + + const handleValuesChange = useCallback( + (newOptions: EuiComboBoxOptionOption[]): void => { + const [newValue] = newOptions.map(({ label }) => optionsMemo[labels.indexOf(label)]); + + handleSpacesWarning(newValue); + handleError(undefined); + handleWarning(undefined); + onChange(newValue ?? ''); + }, + [handleError, handleWarning, handleSpacesWarning, labels, onChange, optionsMemo] + ); + + const handleSearchChange = useCallback( + (searchVal: string): void => { + if (searchVal !== '' && selectedField != null) { + const err = paramIsValid(searchVal, selectedField, isRequired, touched); + handleError(err); + handleWarning(warning); + + if (!err) handleSpacesWarning(searchVal); + } + + if (searchVal) { + // Clear selected option when user types to allow user to modify value without {backspace} + onChange(''); + } + + // Update search query unconditionally to show correct suggestions even when input is cleared + setSearchQuery(searchVal); + }, + [ + selectedField, + onChange, + isRequired, + touched, + handleError, + handleWarning, + warning, + handleSpacesWarning, + ] + ); + + const handleCreateOption = useCallback( + (option: string): boolean | undefined => { + const err = paramIsValid(option, selectedField, isRequired, touched); + handleError(err); + handleWarning(warning); + + if (err != null) { + // Explicitly reject the user's input + setShowSpacesWarning(false); + return false; + } + + handleSpacesWarning(option); + onChange(option); + return undefined; + }, + [ + isRequired, + onChange, + selectedField, + touched, + handleError, + handleSpacesWarning, + handleWarning, + warning, + ] + ); + + const handleNonComboBoxInputChange = useCallback( + (event: React.ChangeEvent): void => { + const newValue = event.target.value; + onChange(newValue); + }, + [onChange] + ); + + const handleBooleanInputChange = useCallback( + (newOption: string): void => { + onChange(newOption); + }, + [onChange] + ); + + const setIsTouchedValue = useCallback((): void => { + setIsTouched(true); + + const err = paramIsValid(selectedValue, selectedField, isRequired, true); + handleError(err); + handleWarning(warning); + }, [setIsTouched, handleError, selectedValue, selectedField, isRequired, warning, handleWarning]); + + const inputPlaceholder = useMemo((): string => { + if (isLoading || isLoadingSuggestions) { + return i18n.LOADING; + } else if (selectedField == null) { + return i18n.SELECT_FIELD_FIRST; + } else { + return placeholder; + } + }, [isLoading, selectedField, isLoadingSuggestions, placeholder]); + + const isLoadingState = useMemo( + (): boolean => isLoading || isLoadingSuggestions, + [isLoading, isLoadingSuggestions] + ); + + useEffect((): void => { + setError(undefined); + if (onError != null) onError(false); + + handleSpacesWarning(selectedValue); + // Looks like selectedField return new object every time when we for example add "and" entry + // that's why we need to check for name and type here + // Probably we should use some kind of memoization on parent components for entries + }, [selectedField?.name, selectedField?.type, selectedValue, handleSpacesWarning, onError]); + + const defaultInput = useMemo((): JSX.Element => { + return ( + + + + ); + }, [ + rowLabel, + error, + selectedField, + showSpacesWarning, + inputPlaceholder, + isDisabled, + isLoadingState, + isClearable, + comboOptions, + selectedComboOptions, + handleValuesChange, + handleSearchChange, + handleCreateOption, + setIsTouchedValue, + warning, + fieldInputWidth, + ariaLabel, + ]); + + if (!isSuggestingValues && selectedField != null) { + switch (selectedField.type) { + case 'number': + return ( + + 0 + ? parseFloat(selectedValue) + : selectedValue ?? '' + } + onChange={handleNonComboBoxInputChange} + data-test-subj="valueAutocompleteFieldMatchNumber" + style={fieldInputWidth ? { width: `${fieldInputWidth}px` } : {}} + aria-label={ariaLabel} + fullWidth + /> + + ); + case 'boolean': + return ( + + + + ); + default: + return defaultInput; + } + } else { + return defaultInput; + } +}; + +AutocompleteFieldMatchComponent.displayName = 'AutocompleteFieldMatch'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.test.tsx new file mode 100644 index 0000000000000..33355e2cb382b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.test.tsx @@ -0,0 +1,398 @@ +/* + * 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 React from 'react'; +import { ReactWrapper, mount } from 'enzyme'; +import { EuiComboBox, EuiComboBoxOptionOption, EuiFormHelpText } from '@elastic/eui'; +import { act, waitFor } from '@testing-library/react'; + +import { AutocompleteFieldMatchAnyComponent } from '.'; +import { getField, fields } from '../fields/index.mock'; +import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; +import { autocompleteStartMock } from '../autocomplete/index.mock'; + +jest.mock('../hooks/use_field_value_autocomplete', () => { + const actual = jest.requireActual('../hooks/use_field_value_autocomplete'); + return { + ...actual, + useFieldValueAutocomplete: jest.fn(), + }; +}); +jest.mock('../translations', () => ({ + FIELD_SPACE_WARNING: 'Warning: there is a space', +})); + +describe('AutocompleteFieldMatchAnyComponent', () => { + let wrapper: ReactWrapper; + const getValueSuggestionsMock = jest + .fn() + .mockResolvedValue([false, true, ['value 3', 'value 4'], jest.fn()]); + + beforeEach(() => { + (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ + false, + true, + ['value 1', 'value 2'], + getValueSuggestionsMock, + ]); + }); + + afterEach(() => { + jest.clearAllMocks(); + wrapper.unmount(); + }); + + test('it renders disabled if "isDisabled" is true', () => { + wrapper = mount( + + ); + + expect( + wrapper.find(`[data-test-subj="valuesAutocompleteMatchAny"] input`).prop('disabled') + ).toBeTruthy(); + }); + + test('it renders loading if "isLoading" is true', () => { + wrapper = mount( + + ); + wrapper.find(`[data-test-subj="valuesAutocompleteMatchAny"] button`).at(0).simulate('click'); + expect( + wrapper + .find(`EuiComboBoxOptionsList[data-test-subj="valuesAutocompleteMatchAny-optionsList"]`) + .prop('isLoading') + ).toBeTruthy(); + }); + + test('it allows user to clear values if "isClearable" is true', () => { + wrapper = mount( + + ); + + expect(wrapper.find(`[data-test-subj="comboBoxClearButton"]`)).toBeTruthy(); + }); + + test('it correctly displays selected value', () => { + wrapper = mount( + + ); + + expect( + wrapper.find(`[data-test-subj="valuesAutocompleteMatchAny"] EuiComboBoxPill`).at(0).text() + ).toEqual('127.0.0.1'); + }); + + test('it invokes "onChange" when new value created', async () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + ( + wrapper.find(EuiComboBox).props() as unknown as { + onCreateOption: (a: string) => void; + } + ).onCreateOption('127.0.0.1'); + + expect(mockOnChange).toHaveBeenCalledWith(['127.0.0.1']); + }); + + test('it invokes "onChange" when new value selected', async () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + ( + wrapper.find(EuiComboBox).props() as unknown as { + onChange: (a: EuiComboBoxOptionOption[]) => void; + } + ).onChange([{ label: 'value 1' }]); + + expect(mockOnChange).toHaveBeenCalledWith(['value 1']); + }); + + test('it refreshes autocomplete with search query when new value searched', () => { + wrapper = mount( + + ); + act(() => { + ( + wrapper.find(EuiComboBox).props() as unknown as { + onSearchChange: (a: string) => void; + } + ).onSearchChange('value 1'); + }); + expect(useFieldValueAutocomplete).toHaveBeenCalledWith({ + autocompleteService: autocompleteStartMock, + fieldValue: [], + indexPattern: { + fields, + id: '1234', + title: 'logstash-*', + }, + operatorType: 'match_any', + query: 'value 1', + selectedField: getField('machine.os.raw'), + }); + }); + test('should show the warning helper text if the new value contains spaces when change', async () => { + (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ + false, + true, + [' value 1 ', 'value 2'], + getValueSuggestionsMock, + ]); + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + await waitFor(() => + ( + wrapper.find(EuiComboBox).props() as unknown as { + onChange: (a: EuiComboBoxOptionOption[]) => void; + } + ).onChange([{ label: ' value 1 ' }]) + ); + wrapper.update(); + expect(mockOnChange).toHaveBeenCalledWith([' value 1 ']); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeTruthy(); + }); + test('should show the warning helper text if the new value contains spaces when searching a new query', () => { + wrapper = mount( + + ); + act(() => { + ( + wrapper.find(EuiComboBox).props() as unknown as { + onSearchChange: (a: string) => void; + } + ).onSearchChange(' value 1'); + }); + + wrapper.update(); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeTruthy(); + expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); + }); + test('should show the warning helper text if selectedValue contains spaces when editing', () => { + wrapper = mount( + + ); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeTruthy(); + expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); + }); + test('should not show the warning helper text if selectedValue is falsy', () => { + wrapper = mount( + + ); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeFalsy(); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.tsx new file mode 100644 index 0000000000000..be7fac088ec1a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_match_any/index.tsx @@ -0,0 +1,252 @@ +/* + * 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 React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui'; +import { uniq } from 'lodash'; +import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; + +// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 +// import { AutocompleteStart } from '../../../../../../../../../../src/plugins/unified_search/public'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AutocompleteStart = any; + +import * as i18n from '../translations'; +import { + getGenericComboBoxProps, + GetGenericComboBoxPropsReturn, +} from '../get_generic_combo_box_props'; +import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; +import { paramIsValid } from '../param_is_valid'; +import { paramContainsSpace } from '../param_contains_space'; + +interface AutocompleteFieldMatchAnyProps { + placeholder: string; + selectedField: DataViewFieldBase | undefined; + selectedValue: string[]; + indexPattern: DataViewBase | undefined; + isLoading: boolean; + isDisabled: boolean; + isClearable: boolean; + isRequired?: boolean; + rowLabel?: string; + autocompleteService: AutocompleteStart; + onChange: (arg: string[]) => void; + onError?: (arg: boolean) => void; + 'aria-label'?: string; +} + +export const AutocompleteFieldMatchAnyComponent: React.FC = ({ + placeholder, + rowLabel, + selectedField, + selectedValue, + indexPattern, + isLoading, + isDisabled = false, + isClearable = false, + isRequired = false, + onChange, + onError, + autocompleteService, + 'aria-label': ariaLabel, +}): JSX.Element => { + const [searchQuery, setSearchQuery] = useState(''); + const [touched, setIsTouched] = useState(false); + const [error, setError] = useState(undefined); + const [showSpacesWarning, setShowSpacesWarning] = useState(false); + const [isLoadingSuggestions, isSuggestingValues, suggestions] = useFieldValueAutocomplete({ + autocompleteService, + fieldValue: selectedValue, + indexPattern, + operatorType: OperatorTypeEnum.MATCH_ANY, + query: searchQuery, + selectedField, + }); + const getLabel = useCallback((option: string): string => option, []); + const optionsMemo = useMemo( + (): string[] => (selectedValue ? uniq([...selectedValue, ...suggestions]) : suggestions), + [suggestions, selectedValue] + ); + const { comboOptions, labels, selectedComboOptions } = useMemo( + (): GetGenericComboBoxPropsReturn => + getGenericComboBoxProps({ + getLabel, + options: optionsMemo, + selectedOptions: selectedValue, + }), + [optionsMemo, selectedValue, getLabel] + ); + const handleSpacesWarning = useCallback( + (params: string[]) => + setShowSpacesWarning(!!params.find((param: string) => paramContainsSpace(param))), + [setShowSpacesWarning] + ); + const handleError = useCallback( + (err: string | undefined): void => { + setError((existingErr): string | undefined => { + const oldErr = existingErr != null; + const newErr = err != null; + if (oldErr !== newErr && onError != null) { + onError(newErr); + } + + return err; + }); + }, + [setError, onError] + ); + + const handleValuesChange = useCallback( + (newOptions: EuiComboBoxOptionOption[]): void => { + const newValues: string[] = newOptions.map(({ label }) => optionsMemo[labels.indexOf(label)]); + handleError(undefined); + handleSpacesWarning(newValues); + onChange(newValues); + }, + [handleError, handleSpacesWarning, labels, onChange, optionsMemo] + ); + + const handleSearchChange = useCallback( + (searchVal: string) => { + if (searchVal === '') { + handleError(undefined); + } + + if (searchVal !== '' && selectedField != null) { + const err = paramIsValid(searchVal, selectedField, isRequired, touched); + handleError(err); + + if (!err) handleSpacesWarning([searchVal]); + + setSearchQuery(searchVal); + } + }, + [handleError, handleSpacesWarning, isRequired, selectedField, touched] + ); + + const handleCreateOption = useCallback( + (option: string): boolean => { + const err = paramIsValid(option, selectedField, isRequired, touched); + handleError(err); + + if (err != null) { + // Explicitly reject the user's input + setShowSpacesWarning(false); + return false; + } + + onChange([...(selectedValue || []), option]); + handleSpacesWarning([option]); + return true; + }, + [handleError, handleSpacesWarning, isRequired, onChange, selectedField, selectedValue, touched] + ); + + const setIsTouchedValue = useCallback((): void => { + handleError(selectedComboOptions.length === 0 ? i18n.FIELD_REQUIRED_ERR : undefined); + setIsTouched(true); + }, [setIsTouched, handleError, selectedComboOptions]); + + const inputPlaceholder = useMemo( + (): string => (isLoading || isLoadingSuggestions ? i18n.LOADING : placeholder), + [isLoading, isLoadingSuggestions, placeholder] + ); + + const isLoadingState = useMemo( + (): boolean => isLoading || isLoadingSuggestions, + [isLoading, isLoadingSuggestions] + ); + useEffect((): void => { + handleSpacesWarning(selectedValue); + }, [selectedField, selectedValue, handleSpacesWarning]); + + const defaultInput = useMemo((): JSX.Element => { + return ( + + + + ); + }, [ + rowLabel, + error, + selectedField, + showSpacesWarning, + inputPlaceholder, + isLoadingState, + isClearable, + isDisabled, + comboOptions, + selectedComboOptions, + handleValuesChange, + handleSearchChange, + handleCreateOption, + setIsTouchedValue, + ariaLabel, + ]); + + if (!isSuggestingValues && selectedField != null) { + switch (selectedField.type) { + case 'number': + return ( + + + + ); + default: + return defaultInput; + } + } + + return defaultInput; +}; + +AutocompleteFieldMatchAnyComponent.displayName = 'AutocompleteFieldMatchAny'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx new file mode 100644 index 0000000000000..2c2411f0a0c11 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx @@ -0,0 +1,514 @@ +/* + * 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 React from 'react'; +import { ReactWrapper, mount } from 'enzyme'; +import { EuiComboBox, EuiComboBoxOptionOption, EuiFormHelpText } from '@elastic/eui'; +import { act, waitFor } from '@testing-library/react'; +import { AutocompleteFieldWildcardComponent } from '.'; +import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; +import { fields, getField } from '../fields/index.mock'; +import { autocompleteStartMock } from '../autocomplete/index.mock'; +import { WILDCARD_WARNING, FILEPATH_WARNING } from '@kbn/securitysolution-utils'; + +jest.mock('../hooks/use_field_value_autocomplete'); +jest.mock('../translations', () => ({ + FIELD_SPACE_WARNING: 'Warning: there is a space', +})); +describe('AutocompleteFieldWildcardComponent', () => { + let wrapper: ReactWrapper; + + const getValueSuggestionsMock = jest + .fn() + .mockResolvedValue([false, true, ['value 3', 'value 4'], jest.fn()]); + + beforeEach(() => { + (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ + false, + true, + ['value 1', 'value 2'], + getValueSuggestionsMock, + ]); + }); + + afterEach(() => { + jest.clearAllMocks(); + wrapper.unmount(); + }); + + test('it renders row label if one passed in', () => { + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="valuesAutocompleteWildcardLabel"] label').at(0).text() + ).toEqual('Row Label'); + }); + + test('it renders disabled if "isDisabled" is true', () => { + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] input').prop('disabled') + ).toBeTruthy(); + }); + + test('it renders loading if "isLoading" is true', () => { + wrapper = mount( + + ); + wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] button').at(0).simulate('click'); + expect( + wrapper + .find('EuiComboBoxOptionsList[data-test-subj="valuesAutocompleteWildcard-optionsList"]') + .prop('isLoading') + ).toBeTruthy(); + }); + + test('it allows user to clear values if "isClearable" is true', () => { + wrapper = mount( + + ); + + expect(wrapper.find(`[data-test-subj="comboBoxClearButton"]`)).toBeTruthy(); + }); + + test('it correctly displays selected value', () => { + wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] input').at(0).props().value + ).toEqual('/opt/*/app.dmg'); + }); + + test('it invokes "onChange" when new value created', async () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + ( + wrapper.find(EuiComboBox).props() as unknown as { + onCreateOption: (a: string) => void; + } + ).onCreateOption('/opt/*/app.dmg'); + + expect(mockOnChange).toHaveBeenCalledWith('/opt/*/app.dmg'); + }); + + test('it invokes "onChange" when new value selected', async () => { + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + ( + wrapper.find(EuiComboBox).props() as unknown as { + onChange: (a: EuiComboBoxOptionOption[]) => void; + } + ).onChange([{ label: 'value 1' }]); + + expect(mockOnChange).toHaveBeenCalledWith('value 1'); + }); + + test('it refreshes autocomplete with search query when new value searched', () => { + wrapper = mount( + + ); + act(() => { + ( + wrapper.find(EuiComboBox).props() as unknown as { + onSearchChange: (a: string) => void; + } + ).onSearchChange('A:\\Some Folder\\inc*.exe'); + }); + + expect(useFieldValueAutocomplete).toHaveBeenCalledWith({ + autocompleteService: autocompleteStartMock, + fieldValue: '', + indexPattern: { + fields, + id: '1234', + title: 'logs-endpoint.events.*', + }, + operatorType: 'wildcard', + query: 'A:\\Some Folder\\inc*.exe', + selectedField: getField('file.path.text'), + }); + }); + + test('it does not invoke "onWarning" when no warning exists', () => { + const mockOnWarning = jest.fn(); + wrapper = mount( + + ); + + act(() => { + ( + wrapper.find(EuiComboBox).props() as unknown as { + onBlur: () => void; + } + ).onBlur(); + }); + + expect(mockOnWarning).not.toHaveBeenCalledWith(true); + }); + + test('it invokes "onWarning" when warning exists', () => { + const mockOnWarning = jest.fn(); + wrapper = mount( + + ); + + act(() => { + ( + wrapper.find(EuiComboBox).props() as unknown as { + onBlur: () => void; + } + ).onBlur(); + }); + + expect(mockOnWarning).toHaveBeenCalledWith(true); + expect( + wrapper + .find('[data-test-subj="valuesAutocompleteWildcardLabel"] div.euiFormHelpText') + .at(0) + .text() + ).toEqual(FILEPATH_WARNING); + }); + + test('it invokes "onWarning" when warning exists and is wildcard warning', () => { + const mockOnWarning = jest.fn(); + wrapper = mount( + + ); + + act(() => { + ( + wrapper.find(EuiComboBox).props() as unknown as { + onBlur: () => void; + } + ).onBlur(); + }); + + expect(mockOnWarning).toHaveBeenCalledWith(true); + const helpText = wrapper + .find('[data-test-subj="valuesAutocompleteWildcardLabel"] div.euiFormHelpText') + .at(0); + expect(helpText.text()).toEqual(WILDCARD_WARNING); + expect(helpText.find('.euiToolTipAnchor')).toBeTruthy(); + }); + test('should show the warning helper text if the new value contains spaces when change', async () => { + (useFieldValueAutocomplete as jest.Mock).mockReturnValue([ + false, + true, + [' value 1 ', 'value 2'], + getValueSuggestionsMock, + ]); + const mockOnChange = jest.fn(); + wrapper = mount( + + ); + + await waitFor(() => + ( + wrapper.find(EuiComboBox).props() as unknown as { + onChange: (a: EuiComboBoxOptionOption[]) => void; + } + ).onChange([{ label: ' value 1 ' }]) + ); + wrapper.update(); + expect(mockOnChange).toHaveBeenCalledWith(' value 1 '); + + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeTruthy(); + }); + test('should show the warning helper text if the new value contains spaces when searching a new query', () => { + wrapper = mount( + + ); + act(() => { + ( + wrapper.find(EuiComboBox).props() as unknown as { + onSearchChange: (a: string) => void; + } + ).onSearchChange(' value 1'); + }); + + wrapper.update(); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeTruthy(); + expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); + }); + test('should show the warning helper text if selectedValue contains spaces when editing', () => { + wrapper = mount( + + ); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeTruthy(); + expect(euiFormHelptext.text()).toEqual('Warning: there is a space'); + }); + test('should not show the warning helper text if selectedValue is falsy', () => { + wrapper = mount( + + ); + const euiFormHelptext = wrapper.find(EuiFormHelpText); + expect(euiFormHelptext.length).toBeFalsy(); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.tsx new file mode 100644 index 0000000000000..c095578bf0ff0 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.tsx @@ -0,0 +1,285 @@ +/* + * 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 React, { useCallback, useMemo, useState, useEffect, memo } from 'react'; +import { EuiFormRow, EuiComboBoxOptionOption, EuiComboBox } from '@elastic/eui'; +import { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; + +import { uniq } from 'lodash'; + +import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; + +// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 +// import { AutocompleteStart } from '../../../../../../../../../../src/plugins/unified_search/public'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AutocompleteStart = any; + +import * as i18n from '../translations'; +import { useFieldValueAutocomplete } from '../hooks/use_field_value_autocomplete'; +import { + getGenericComboBoxProps, + GetGenericComboBoxPropsReturn, +} from '../get_generic_combo_box_props'; +import { paramIsValid } from '../param_is_valid'; +import { paramContainsSpace } from '../param_contains_space'; + +const SINGLE_SELECTION = { asPlainText: true }; + +type Warning = string | React.ReactNode; +interface AutocompleteFieldWildcardProps { + placeholder: string; + selectedField: DataViewFieldBase | undefined; + selectedValue: string | undefined; + indexPattern: DataViewBase | undefined; + isLoading: boolean; + isDisabled?: boolean; + isClearable?: boolean; + isRequired?: boolean; + fieldInputWidth?: number; + rowLabel?: string; + autocompleteService: AutocompleteStart; + onChange: (arg: string) => void; + onError: (arg: boolean) => void; + onWarning: (arg: boolean) => void; + warning?: Warning; + 'aria-label'?: string; +} + +export const AutocompleteFieldWildcardComponent: React.FC = memo( + ({ + autocompleteService, + placeholder, + rowLabel, + selectedField, + selectedValue, + indexPattern, + isLoading, + isDisabled = false, + isClearable = false, + isRequired = false, + fieldInputWidth, + onChange, + onError, + onWarning, + warning, + 'aria-label': ariaLabel, + }): JSX.Element => { + const [searchQuery, setSearchQuery] = useState(''); + const [touched, setIsTouched] = useState(false); + const [error, setError] = useState(undefined); + const [showSpacesWarning, setShowSpacesWarning] = useState(false); + const [isLoadingSuggestions, , suggestions] = useFieldValueAutocomplete({ + autocompleteService, + fieldValue: selectedValue, + indexPattern, + operatorType: OperatorTypeEnum.WILDCARD, + query: searchQuery, + selectedField, + }); + const getLabel = useCallback((option: string): string => option, []); + const optionsMemo = useMemo((): string[] => { + const valueAsStr = String(selectedValue); + return selectedValue != null && selectedValue.trim() !== '' + ? uniq([valueAsStr, ...suggestions]) + : suggestions; + }, [suggestions, selectedValue]); + const selectedOptionsMemo = useMemo((): string[] => { + const valueAsStr = String(selectedValue); + return selectedValue ? [valueAsStr] : []; + }, [selectedValue]); + + const handleSpacesWarning = useCallback( + (param: string | undefined) => { + if (!param) return setShowSpacesWarning(false); + setShowSpacesWarning(!!paramContainsSpace(param)); + }, + [setShowSpacesWarning] + ); + const handleError = useCallback( + (err: string | undefined): void => { + setError((existingErr): string | undefined => { + const oldErr = existingErr != null; + const newErr = err != null; + if (oldErr !== newErr && onError != null) { + onError(newErr); + } + + return err; + }); + }, + [setError, onError] + ); + + const handleWarning = useCallback( + (warn: Warning | undefined): void => { + onWarning(warn !== undefined); + }, + [onWarning] + ); + + const { comboOptions, labels, selectedComboOptions } = useMemo( + (): GetGenericComboBoxPropsReturn => + getGenericComboBoxProps({ + getLabel, + options: optionsMemo, + selectedOptions: selectedOptionsMemo, + }), + [optionsMemo, selectedOptionsMemo, getLabel] + ); + + const handleValuesChange = useCallback( + (newOptions: EuiComboBoxOptionOption[]): void => { + const [newValue] = newOptions.map(({ label }) => optionsMemo[labels.indexOf(label)]); + handleError(undefined); + handleSpacesWarning(newValue); + setShowSpacesWarning(false); + + onChange(newValue ?? ''); + }, + [handleError, handleSpacesWarning, labels, onChange, optionsMemo] + ); + + const handleSearchChange = useCallback( + (searchVal: string): void => { + if (searchVal.trim() !== '' && selectedField != null) { + const err = paramIsValid(searchVal, selectedField, isRequired, touched); + handleError(err); + handleWarning(warning); + if (!err) handleSpacesWarning(searchVal); + + setSearchQuery(searchVal); + } + }, + [handleError, handleSpacesWarning, isRequired, selectedField, touched, warning, handleWarning] + ); + + const handleCreateOption = useCallback( + (option: string): boolean | undefined => { + const err = paramIsValid(option, selectedField, isRequired, touched); + handleError(err); + handleWarning(warning); + + if (err != null) { + // Explicitly reject the user's input + setShowSpacesWarning(false); + return false; + } + + handleSpacesWarning(option); + onChange(option); + return undefined; + }, + [ + isRequired, + handleSpacesWarning, + onChange, + selectedField, + touched, + handleError, + handleWarning, + warning, + ] + ); + + const setIsTouchedValue = useCallback((): void => { + setIsTouched(true); + + const err = paramIsValid(selectedValue, selectedField, isRequired, true); + handleError(err); + handleWarning(warning); + }, [ + setIsTouched, + handleError, + selectedValue, + selectedField, + isRequired, + handleWarning, + warning, + ]); + + const inputPlaceholder = useMemo((): string => { + if (isLoading || isLoadingSuggestions) { + return i18n.LOADING; + } else if (selectedField == null) { + return i18n.SELECT_FIELD_FIRST; + } else { + return placeholder; + } + }, [isLoading, selectedField, isLoadingSuggestions, placeholder]); + + const isLoadingState = useMemo( + (): boolean => isLoading || isLoadingSuggestions, + [isLoading, isLoadingSuggestions] + ); + + useEffect((): void => { + setError(undefined); + if (onError != null) { + onError(false); + } + handleSpacesWarning(selectedValue); + + onWarning(false); + }, [selectedField, selectedValue, onError, onWarning, handleSpacesWarning]); + + const defaultInput = useMemo((): JSX.Element => { + return ( + + + + ); + }, [ + rowLabel, + error, + warning, + showSpacesWarning, + selectedField, + inputPlaceholder, + isDisabled, + isLoadingState, + isClearable, + comboOptions, + selectedComboOptions, + handleValuesChange, + handleSearchChange, + handleCreateOption, + setIsTouchedValue, + fieldInputWidth, + ariaLabel, + ]); + + return defaultInput; + } +); + +AutocompleteFieldWildcardComponent.displayName = 'AutocompleteFieldWildcard'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts new file mode 100644 index 0000000000000..32e9d60197868 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/fields/index.mock.ts @@ -0,0 +1,321 @@ +/* + * 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 { DataViewFieldBase } from '@kbn/es-query'; + +// Copied from "src/plugins/data/common/index_patterns/fields/fields.mocks.ts" but with the types changed to "DataViewFieldBase" since that type is compatible. +// TODO: This should move out once those mocks are directly useable or in their own package, https://github.com/elastic/kibana/issues/100715 + +export const fields: DataViewFieldBase[] = [ + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'ssl', + type: 'boolean', + esTypes: ['boolean'], + count: 20, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: '@timestamp', + type: 'date', + esTypes: ['date'], + count: 30, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'time', + type: 'date', + esTypes: ['date'], + count: 30, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: '@tags', + type: 'string', + esTypes: ['keyword'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'utc_time', + type: 'date', + esTypes: ['date'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'phpmemory', + type: 'number', + esTypes: ['integer'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'ip', + type: 'ip', + esTypes: ['ip'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'request_body', + type: 'attachment', + esTypes: ['attachment'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'point', + type: 'geo_point', + esTypes: ['geo_point'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'area', + type: 'geo_shape', + esTypes: ['geo_shape'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'hashed', + type: 'murmur3', + esTypes: ['murmur3'], + count: 0, + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + }, + { + name: 'geo.coordinates', + type: 'geo_point', + esTypes: ['geo_point'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'extension', + type: 'string', + esTypes: ['keyword'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'machine.os', + type: 'string', + esTypes: ['text'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + name: 'machine.os.raw', + type: 'string', + esTypes: ['keyword'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: { multi: { parent: 'machine.os' } }, + }, + { + name: 'geo.src', + type: 'string', + esTypes: ['keyword'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: '_id', + type: 'string', + esTypes: ['_id'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + name: '_type', + type: 'string', + esTypes: ['_type'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + name: '_source', + type: '_source', + esTypes: ['_source'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + name: 'non-filterable', + type: 'string', + esTypes: ['text'], + count: 0, + scripted: false, + searchable: false, + aggregatable: true, + readFromDocValues: false, + }, + { + name: 'non-sortable', + type: 'string', + esTypes: ['text'], + count: 0, + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: false, + }, + { + name: 'custom_user_field', + type: 'conflict', + esTypes: ['long', 'text'], + count: 0, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + name: 'script string', + type: 'string', + count: 0, + scripted: true, + script: "'i am a string'", + lang: 'expression', + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + name: 'script number', + type: 'number', + count: 0, + scripted: true, + script: '1234', + lang: 'expression', + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + name: 'script date', + type: 'date', + count: 0, + scripted: true, + script: '1234', + lang: 'painless', + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + name: 'script murmur3', + type: 'murmur3', + count: 0, + scripted: true, + script: '1234', + lang: 'expression', + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + name: 'nestedField.child', + type: 'string', + esTypes: ['text'], + count: 0, + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + subType: { nested: { path: 'nestedField' } }, + }, + { + name: 'nestedField.nestedChild.doublyNestedChild', + type: 'string', + esTypes: ['text'], + count: 0, + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + subType: { nested: { path: 'nestedField.nestedChild' } }, + }, + { + name: 'file.path.text', + type: 'string', + esTypes: ['text'], + searchable: true, + aggregatable: false, + subType: { multi: { parent: 'file.path' } }, + }, +] as unknown as DataViewFieldBase[]; + +export const getField = (name: string) => fields.find((field) => field.name === name); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.test.ts new file mode 100644 index 0000000000000..3328af4e2fa2c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.test.ts @@ -0,0 +1,123 @@ +/* + * 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 { filterFieldToList } from '.'; + +import { getListResponseMock } from '../list_schema/index.mock'; +import { DataViewFieldBase } from '@kbn/es-query'; +import { AutocompleteListsData } from '../field_value_lists'; + +const emptyListData: AutocompleteListsData = { smallLists: [], largeLists: [] }; + +describe('#filterFieldToList', () => { + test('it returns empty list data object if given a undefined for field', () => { + const filter = filterFieldToList(emptyListData, undefined); + expect(filter).toEqual(emptyListData); + }); + + test('it returns empty list data object if filed does not contain esTypes', () => { + const field: DataViewFieldBase = { + name: 'some-name', + type: 'some-type', + }; + const filter = filterFieldToList(emptyListData, field); + expect(filter).toEqual(emptyListData); + }); + + test('it returns filtered lists of ip_range -> ip', () => { + const field: DataViewFieldBase & { esTypes: string[] } = { + esTypes: ['ip'], + name: 'some-name', + type: 'ip', + }; + const listData: AutocompleteListsData = { + smallLists: [{ ...getListResponseMock(), type: 'ip_range' }], + largeLists: [], + }; + const filter = filterFieldToList(listData, field); + const expected = listData; + expect(filter).toEqual(expected); + }); + + test('it returns filtered lists of ip -> ip', () => { + const field: DataViewFieldBase & { esTypes: string[] } = { + esTypes: ['ip'], + name: 'some-name', + type: 'ip', + }; + const listData: AutocompleteListsData = { + smallLists: [{ ...getListResponseMock(), type: 'ip' }], + largeLists: [], + }; + const filter = filterFieldToList(listData, field); + const expected = listData; + expect(filter).toEqual(expected); + }); + + test('it returns filtered lists of keyword -> keyword', () => { + const field: DataViewFieldBase & { esTypes: string[] } = { + esTypes: ['keyword'], + name: 'some-name', + type: 'keyword', + }; + const listData: AutocompleteListsData = { + smallLists: [{ ...getListResponseMock(), type: 'keyword' }], + largeLists: [], + }; + const filter = filterFieldToList(listData, field); + const expected = listData; + expect(filter).toEqual(expected); + }); + + test('it returns filtered lists of text -> text', () => { + const field: DataViewFieldBase & { esTypes: string[] } = { + esTypes: ['text'], + name: 'some-name', + type: 'text', + }; + const listData: AutocompleteListsData = { + smallLists: [{ ...getListResponseMock(), type: 'text' }], + largeLists: [], + }; + const filter = filterFieldToList(listData, field); + const expected = listData; + expect(filter).toEqual(expected); + }); + + test('it returns small and large filtered lists of ip_range -> ip', () => { + const field: DataViewFieldBase & { esTypes: string[] } = { + esTypes: ['ip'], + name: 'some-name', + type: 'ip', + }; + const listData: AutocompleteListsData = { + smallLists: [{ ...getListResponseMock(), type: 'ip_range' }], + largeLists: [{ ...getListResponseMock(), type: 'ip_range' }], + }; + const filter = filterFieldToList(listData, field); + const expected = listData; + expect(filter).toEqual(expected); + }); + + test('it returns 1 filtered lists of ip_range -> ip if the 2nd is not compatible type', () => { + const field: DataViewFieldBase & { esTypes: string[] } = { + esTypes: ['ip'], + name: 'some-name', + type: 'ip', + }; + const listData: AutocompleteListsData = { + smallLists: [{ ...getListResponseMock(), type: 'ip_range' }], + largeLists: [{ ...getListResponseMock(), type: 'text' }], + }; + const filter = filterFieldToList(listData, field); + const expected: AutocompleteListsData = { + smallLists: [{ ...getListResponseMock(), type: 'ip_range' }], + largeLists: [], + }; + expect(filter).toEqual(expected); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.ts new file mode 100644 index 0000000000000..a4df119766a96 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/filter_field_to_list/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DataViewFieldBase } from '@kbn/es-query'; +import { typeMatch } from '../type_match'; +import { AutocompleteListsData } from '../field_value_lists'; + +/** + * Given an array of lists and optionally a field this will return all + * the lists that match against the field based on the types from the field + * + * NOTE: That we support one additional property from "FieldSpec" located here: + * src/plugins/data/common/index_patterns/fields/types.ts + * This type property is esTypes. If it exists and is on there we will read off the esTypes. + * @param lists The lists to match against the field + * @param field The field to check against the list to see if they are compatible + */ +export const filterFieldToList = ( + lists: AutocompleteListsData, + field?: DataViewFieldBase & { esTypes?: string[] } +): AutocompleteListsData => { + if (field != null) { + const { esTypes = [] } = field; + return { + smallLists: lists.smallLists.filter(({ type }) => + esTypes.some((esType: string) => typeMatch(type, esType)) + ), + largeLists: lists.largeLists.filter(({ type }) => + esTypes.some((esType: string) => typeMatch(type, esType)) + ), + }; + } else { + return { smallLists: [], largeLists: [] }; + } +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.test.tsx new file mode 100644 index 0000000000000..f333e7c6ebdd2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.test.tsx @@ -0,0 +1,124 @@ +/* + * 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 { getGenericComboBoxProps } from '.'; + +describe('get_generic_combo_box_props', () => { + test('it returns empty arrays if "options" is empty array', () => { + const result = getGenericComboBoxProps({ + options: [], + selectedOptions: ['option1'], + getLabel: (t: string) => t, + }); + + expect(result).toEqual({ comboOptions: [], labels: [], selectedComboOptions: [] }); + }); + + test('it returns formatted props if "options" array is not empty', () => { + const result = getGenericComboBoxProps({ + options: ['option1', 'option2', 'option3'], + selectedOptions: [], + getLabel: (t: string) => t, + }); + + expect(result).toEqual({ + comboOptions: [ + { + label: 'option1', + }, + { + label: 'option2', + }, + { + label: 'option3', + }, + ], + labels: ['option1', 'option2', 'option3'], + selectedComboOptions: [], + }); + }); + + test('it does not return "selectedOptions" items that do not appear in "options"', () => { + const result = getGenericComboBoxProps({ + options: ['option1', 'option2', 'option3'], + selectedOptions: ['option4'], + getLabel: (t: string) => t, + }); + + expect(result).toEqual({ + comboOptions: [ + { + label: 'option1', + }, + { + label: 'option2', + }, + { + label: 'option3', + }, + ], + labels: ['option1', 'option2', 'option3'], + selectedComboOptions: [], + }); + }); + + test('it returns "selectedOptions" items that do appear in "options"', () => { + const result = getGenericComboBoxProps({ + options: ['option1', 'option2', 'option3'], + selectedOptions: ['option2'], + getLabel: (t: string) => t, + }); + + expect(result).toEqual({ + comboOptions: [ + { + label: 'option1', + }, + { + label: 'option2', + }, + { + label: 'option3', + }, + ], + labels: ['option1', 'option2', 'option3'], + selectedComboOptions: [ + { + label: 'option2', + }, + ], + }); + }); + + test('it returns "disabledOptions" items that do appear in "options" as disabled', () => { + const result = getGenericComboBoxProps({ + options: ['option1', 'option2', 'option3'], + selectedOptions: [], + disabledOptions: ['option2'], + getLabel: (t: string) => t, + }); + + expect(result).toEqual({ + comboOptions: [ + { + label: 'option1', + disabled: false, + }, + { + label: 'option2', + disabled: true, + }, + { + label: 'option3', + disabled: false, + }, + ], + labels: ['option1', 'option2', 'option3'], + selectedComboOptions: [], + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.ts new file mode 100644 index 0000000000000..f043fc978836d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_generic_combo_box_props/index.ts @@ -0,0 +1,53 @@ +/* + * 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 { EuiComboBoxOptionOption } from '@elastic/eui'; + +export interface GetGenericComboBoxPropsReturn { + comboOptions: EuiComboBoxOptionOption[]; + labels: string[]; + selectedComboOptions: EuiComboBoxOptionOption[]; +} + +/** + * Determines the options, selected values and option labels for EUI combo box + * @param options options user can select from + * @param selectedOptions user selection if any + * @param getLabel helper function to know which property to use for labels + */ +export const getGenericComboBoxProps = ({ + getLabel, + options, + selectedOptions, + disabledOptions, +}: { + getLabel: (value: T) => string; + options: T[]; + selectedOptions: T[]; + disabledOptions?: T[]; +}): GetGenericComboBoxPropsReturn => { + const newLabels = options.map(getLabel); + const disabledLabels = disabledOptions?.map(getLabel); + const newComboOptions: EuiComboBoxOptionOption[] = newLabels.map((label) => ({ + label, + disabled: disabledLabels && disabledLabels.length !== 0 && disabledLabels.includes(label), + })); + const newSelectedComboOptions = selectedOptions + .map(getLabel) + .filter((option) => { + return newLabels.indexOf(option) !== -1; + }) + .map((option) => { + return newComboOptions[newLabels.indexOf(option)]; + }); + + return { + comboOptions: newComboOptions, + labels: newLabels, + selectedComboOptions: newSelectedComboOptions, + }; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts new file mode 100644 index 0000000000000..db031a65e0bb7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_operators/index.test.ts @@ -0,0 +1,57 @@ +/* + * 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 { + doesNotExistOperator, + EVENT_FILTERS_OPERATORS, + ALL_OPERATORS, + existsOperator, + isNotOperator, + isOperator, +} from '@kbn/securitysolution-list-utils'; +import { getOperators } from '.'; +import { getField } from '../fields/index.mock'; + +describe('#getOperators', () => { + test('it returns "isOperator" if passed in field is "undefined"', () => { + const operator = getOperators(undefined); + + expect(operator).toEqual([isOperator]); + }); + + test('it returns expected operators when field type is "boolean"', () => { + const operator = getOperators(getField('ssl')); + + expect(operator).toEqual([isOperator, isNotOperator, existsOperator, doesNotExistOperator]); + }); + + test('it returns "isOperator" when field type is "nested"', () => { + const operator = getOperators({ + name: 'nestedField', + scripted: false, + subType: { nested: { path: 'nestedField' } }, + type: 'nested', + }); + + expect(operator).toEqual([isOperator]); + }); + + test('it includes a "matches" operator when field is "file.path.text"', () => { + const operator = getOperators({ + name: 'file.path.text', + type: 'simple', + }); + + expect(operator).toEqual(EVENT_FILTERS_OPERATORS); + }); + + test('it returns all operator types when field type is not null, boolean, or nested', () => { + const operator = getOperators(getField('machine.os.raw')); + + expect(operator).toEqual(ALL_OPERATORS); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts new file mode 100644 index 0000000000000..451d4f5c21a7c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/get_operators/index.ts @@ -0,0 +1,38 @@ +/* + * 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 { DataViewFieldBase } from '@kbn/es-query'; + +import { + ALL_OPERATORS, + EVENT_FILTERS_OPERATORS, + OperatorOption, + doesNotExistOperator, + existsOperator, + isNotOperator, + isOperator, +} from '@kbn/securitysolution-list-utils'; + +/** + * Returns the appropriate operators given a field type + * + * @param field DataViewFieldBase selected field + * + */ +export const getOperators = (field: DataViewFieldBase | undefined): OperatorOption[] => { + if (field == null) { + return [isOperator]; + } else if (field.type === 'boolean') { + return [isOperator, isNotOperator, existsOperator, doesNotExistOperator]; + } else if (field.type === 'nested') { + return [isOperator]; + } else if (field.name === 'file.path.text') { + return EVENT_FILTERS_OPERATORS; + } else { + return ALL_OPERATORS; + } +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/hooks/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/hooks/index.ts new file mode 100644 index 0000000000000..e9d4507b14005 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/hooks/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './use_field_value_autocomplete'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.test.ts new file mode 100644 index 0000000000000..7d776db124134 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.test.ts @@ -0,0 +1,298 @@ +/* + * 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 { waitFor, renderHook } from '@testing-library/react'; +import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; + +import { UseFieldValueAutocompleteReturn, useFieldValueAutocomplete } from '.'; +import { getField } from '../../fields/index.mock'; +import { autocompleteStartMock } from '../../autocomplete/index.mock'; +import { DataViewFieldBase } from '@kbn/es-query'; + +// Copied from "src/plugins/data/common/index_patterns/index_pattern.stub.ts" +// TODO: Remove this in favor of the above if/when it is ported, https://github.com/elastic/kibana/issues/100715 +export const stubIndexPatternWithFields = { + id: '1234', + title: 'logstash-*', + fields: [ + { + name: 'response', + type: 'number', + esTypes: ['integer'], + aggregatable: true, + filterable: true, + searchable: true, + }, + ], +}; + +describe('use_field_value_autocomplete', () => { + const onErrorMock = jest.fn(); + const getValueSuggestionsMock = jest.fn().mockResolvedValue(['value 1', 'value 2']); + + afterEach(() => { + onErrorMock.mockClear(); + getValueSuggestionsMock.mockClear(); + }); + + test('initializes hook', async () => { + const { result } = renderHook(() => + useFieldValueAutocomplete({ + autocompleteService: { + ...autocompleteStartMock, + getValueSuggestions: getValueSuggestionsMock, + }, + fieldValue: '', + indexPattern: undefined, + operatorType: OperatorTypeEnum.MATCH, + query: '', + selectedField: undefined, + }) + ); + await waitFor(() => expect(result.current).toEqual([false, true, [], result.current[3]])); + }); + + test('does not call autocomplete service if "operatorType" is "exists"', async () => { + const { result } = renderHook(() => + useFieldValueAutocomplete({ + autocompleteService: { + ...autocompleteStartMock, + getValueSuggestions: getValueSuggestionsMock, + }, + fieldValue: '', + indexPattern: stubIndexPatternWithFields, + operatorType: OperatorTypeEnum.EXISTS, + query: '', + selectedField: getField('machine.os'), + }) + ); + + await waitFor(() => { + const expectedResult: UseFieldValueAutocompleteReturn = [false, true, [], result.current[3]]; + + expect(result.current).toEqual(expectedResult); + expect(getValueSuggestionsMock).not.toHaveBeenCalled(); + }); + }); + + test('does not call autocomplete service if "selectedField" is undefined', async () => { + const { result } = renderHook(() => + useFieldValueAutocomplete({ + autocompleteService: { + ...autocompleteStartMock, + getValueSuggestions: getValueSuggestionsMock, + }, + fieldValue: '', + indexPattern: stubIndexPatternWithFields, + operatorType: OperatorTypeEnum.EXISTS, + query: '', + selectedField: undefined, + }) + ); + + await waitFor(() => { + const expectedResult: UseFieldValueAutocompleteReturn = [false, true, [], result.current[3]]; + + expect(result.current).toEqual(expectedResult); + expect(getValueSuggestionsMock).not.toHaveBeenCalled(); + }); + }); + + test('does not call autocomplete service if "indexPattern" is undefined', async () => { + const { result } = renderHook(() => + useFieldValueAutocomplete({ + autocompleteService: { + ...autocompleteStartMock, + getValueSuggestions: getValueSuggestionsMock, + }, + fieldValue: '', + indexPattern: undefined, + operatorType: OperatorTypeEnum.EXISTS, + query: '', + selectedField: getField('machine.os'), + }) + ); + + await waitFor(() => { + const expectedResult: UseFieldValueAutocompleteReturn = [false, true, [], result.current[3]]; + + expect(result.current).toEqual(expectedResult); + expect(getValueSuggestionsMock).not.toHaveBeenCalled(); + }); + }); + + test('it uses full path name for nested fields to fetch suggestions', async () => { + const suggestionsMock = jest.fn().mockResolvedValue([]); + + const selectedField: DataViewFieldBase | undefined = getField('nestedField.child'); + if (selectedField == null) { + throw new TypeError('selectedField for this test should always be defined'); + } + + const { signal } = new AbortController(); + renderHook(() => + useFieldValueAutocomplete({ + autocompleteService: { + ...autocompleteStartMock, + getValueSuggestions: suggestionsMock, + }, + fieldValue: '', + indexPattern: stubIndexPatternWithFields, + operatorType: OperatorTypeEnum.MATCH, + query: '', + selectedField: { ...selectedField, name: 'child' }, + }) + ); + + await waitFor(() => + expect(suggestionsMock).toHaveBeenCalledWith({ + field: { ...getField('nestedField.child'), name: 'nestedField.child' }, + indexPattern: { + fields: [ + { + aggregatable: true, + esTypes: ['integer'], + filterable: true, + name: 'response', + searchable: true, + type: 'number', + }, + ], + id: '1234', + title: 'logstash-*', + }, + query: '', + signal, + useTimeRange: false, + }) + ); + }); + + test('returns "isSuggestingValues" of false if field type is boolean', async () => { + const { result } = renderHook(() => + useFieldValueAutocomplete({ + autocompleteService: { + ...autocompleteStartMock, + getValueSuggestions: getValueSuggestionsMock, + }, + fieldValue: '', + indexPattern: stubIndexPatternWithFields, + operatorType: OperatorTypeEnum.MATCH, + query: '', + selectedField: getField('ssl'), + }) + ); + + await waitFor(() => { + const expectedResult: UseFieldValueAutocompleteReturn = [false, false, [], result.current[3]]; + + expect(result.current).toEqual(expectedResult); + expect(getValueSuggestionsMock).not.toHaveBeenCalled(); + }); + }); + + test('returns "isSuggestingValues" of false to note that autocomplete service is not in use if no autocomplete suggestions available', async () => { + const suggestionsMock = jest.fn().mockResolvedValue([]); + + const { result } = renderHook(() => + useFieldValueAutocomplete({ + autocompleteService: { + ...autocompleteStartMock, + getValueSuggestions: suggestionsMock, + }, + fieldValue: '', + indexPattern: stubIndexPatternWithFields, + operatorType: OperatorTypeEnum.MATCH, + query: '', + selectedField: getField('bytes'), + }) + ); + + await waitFor(() => { + const expectedResult: UseFieldValueAutocompleteReturn = [false, false, [], result.current[3]]; + + expect(suggestionsMock).toHaveBeenCalled(); + expect(result.current).toEqual(expectedResult); + }); + }); + + test('returns suggestions', async () => { + const { signal } = new AbortController(); + const { result } = renderHook(() => + useFieldValueAutocomplete({ + autocompleteService: { + ...autocompleteStartMock, + getValueSuggestions: getValueSuggestionsMock, + }, + fieldValue: '', + indexPattern: stubIndexPatternWithFields, + operatorType: OperatorTypeEnum.MATCH, + query: '', + selectedField: getField('@tags'), + }) + ); + + await waitFor(() => { + const expectedResult: UseFieldValueAutocompleteReturn = [ + false, + true, + ['value 1', 'value 2'], + result.current[3], + ]; + + expect(getValueSuggestionsMock).toHaveBeenCalledWith({ + field: getField('@tags'), + indexPattern: stubIndexPatternWithFields, + query: '', + signal, + useTimeRange: false, + }); + expect(result.current).toEqual(expectedResult); + }); + }); + + test('returns new suggestions on subsequent calls', async () => { + const { result } = renderHook(() => + useFieldValueAutocomplete({ + autocompleteService: { + ...autocompleteStartMock, + getValueSuggestions: getValueSuggestionsMock, + }, + fieldValue: '', + indexPattern: stubIndexPatternWithFields, + operatorType: OperatorTypeEnum.MATCH, + query: '', + selectedField: getField('@tags'), + }) + ); + + await waitFor(() => expect(result.current[3]).not.toBeNull()); + + // Added check for typescripts sake, if null, + // would not reach below logic as test would stop above + if (result.current[3] != null) { + result.current[3]({ + fieldSelected: getField('@tags'), + patterns: stubIndexPatternWithFields, + searchQuery: '', + value: 'hello', + }); + } + + await waitFor(() => { + const expectedResult: UseFieldValueAutocompleteReturn = [ + false, + true, + ['value 1', 'value 2'], + result.current[3], + ]; + + expect(getValueSuggestionsMock).toHaveBeenCalledTimes(2); + expect(result.current).toEqual(expectedResult); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.ts new file mode 100644 index 0000000000000..dbbe321014e2b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/hooks/use_field_value_autocomplete/index.ts @@ -0,0 +1,122 @@ +/* + * 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 { useEffect, useRef, useState } from 'react'; +import { debounce } from 'lodash'; +import { ListOperatorTypeEnum as OperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import { DataViewBase, DataViewFieldBase, getDataViewFieldSubtypeNested } from '@kbn/es-query'; + +// TODO: I have to use any here for now, but once this is available below, we should use the correct types, https://github.com/elastic/kibana/issues/100715 +// import { AutocompleteStart } from '../../../../../../../../../../../src/plugins/unified_search/public'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AutocompleteStart = any; + +interface FuncArgs { + fieldSelected: DataViewFieldBase | undefined; + patterns: DataViewBase | undefined; + searchQuery: string; + value: string | string[] | undefined; +} + +type Func = (args: FuncArgs) => void; + +export type UseFieldValueAutocompleteReturn = [boolean, boolean, string[], Func | null]; + +export interface UseFieldValueAutocompleteProps { + autocompleteService: AutocompleteStart; + fieldValue: string | string[] | undefined; + indexPattern: DataViewBase | undefined; + operatorType: OperatorTypeEnum; + query: string; + selectedField: DataViewFieldBase | undefined; +} +/** + * Hook for using the field value autocomplete service + */ +export const useFieldValueAutocomplete = ({ + selectedField, + operatorType, + fieldValue, + query, + indexPattern, + autocompleteService, +}: UseFieldValueAutocompleteProps): UseFieldValueAutocompleteReturn => { + const [isLoading, setIsLoading] = useState(false); + const [isSuggestingValues, setIsSuggestingValues] = useState(true); + const [suggestions, setSuggestions] = useState([]); + const updateSuggestions = useRef(null); + + useEffect(() => { + let isSubscribed = true; + const abortCtrl = new AbortController(); + + const fetchSuggestions = debounce( + async ({ fieldSelected, patterns, searchQuery }: FuncArgs) => { + try { + if (isSubscribed) { + if (fieldSelected == null || patterns == null) { + return; + } + + if (fieldSelected.type === 'boolean') { + setIsSuggestingValues(false); + return; + } + + setIsLoading(true); + const subTypeNested = getDataViewFieldSubtypeNested(fieldSelected); + const field = subTypeNested + ? { + ...fieldSelected, + name: `${subTypeNested.nested.path}.${fieldSelected.name}`, + } + : fieldSelected; + + const newSuggestions = await autocompleteService.getValueSuggestions({ + field, + indexPattern: patterns, + query: searchQuery, + signal: abortCtrl.signal, + useTimeRange: false, + }); + + if (newSuggestions.length === 0) { + setIsSuggestingValues(false); + } + + setIsLoading(false); + setSuggestions([...newSuggestions]); + } + } catch (error) { + if (isSubscribed) { + setSuggestions([]); + setIsLoading(false); + } + } + }, + 500 + ); + + if (operatorType !== OperatorTypeEnum.EXISTS) { + fetchSuggestions({ + fieldSelected: selectedField, + patterns: indexPattern, + searchQuery: query, + value: fieldValue, + }); + } + + updateSuggestions.current = fetchSuggestions; + + return (): void => { + isSubscribed = false; + abortCtrl.abort(); + }; + }, [selectedField, operatorType, fieldValue, indexPattern, query, autocompleteService]); + + return [isLoading, isSuggestingValues, suggestions, updateSuggestions.current]; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/list_schema/index.mock.ts new file mode 100644 index 0000000000000..aade602f1950c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/list_schema/index.mock.ts @@ -0,0 +1,60 @@ +/* + * 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 { + FoundListSchema, + ListSchema, + FoundListsBySizeSchema, +} from '@kbn/securitysolution-io-ts-list-types'; + +// TODO: Once this mock is available within packages, use it instead, https://github.com/elastic/kibana/issues/100715 +// import { getFoundListSchemaMock } from '../../../../../../../../lists/common/schemas/response/found_list_schema.mock'; +export const getFoundListSchemaMock = (): FoundListSchema => ({ + cursor: '123', + data: [getListResponseMock()], + page: 1, + per_page: 1, + total: 1, +}); + +export const getFoundListsBySizeSchemaMock = (): FoundListsBySizeSchema => ({ + smallLists: [getListResponseMock()], + largeLists: [getListResponseMock()], +}); + +// TODO: Once these mocks are available from packages use it instead, https://github.com/elastic/kibana/issues/100715 +export const DATE_NOW = '2020-04-20T15:25:31.830Z'; +export const USER = 'some user'; +export const IMMUTABLE = false; +export const VERSION = 1; +export const DESCRIPTION = 'some description'; +export const TIE_BREAKER = '6a76b69d-80df-4ab2-8c3e-85f466b06a0e'; +export const LIST_ID = 'some-list-id'; +export const META = {}; +export const TYPE = 'ip'; +export const NAME = 'some name'; + +// TODO: Once this mock is available within packages, use it instead, https://github.com/elastic/kibana/issues/100715 +// import { getListResponseMock } from '../../../../../../../../lists/common/schemas/response/list_schema.mock'; +export const getListResponseMock = (): ListSchema => ({ + '@timestamp': DATE_NOW, + _version: undefined, + created_at: DATE_NOW, + created_by: USER, + description: DESCRIPTION, + deserializer: undefined, + id: LIST_ID, + immutable: IMMUTABLE, + meta: META, + name: NAME, + serializer: undefined, + tie_breaker_id: TIE_BREAKER, + type: TYPE, + updated_at: DATE_NOW, + updated_by: USER, + version: VERSION, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx new file mode 100644 index 0000000000000..eef8738b67c51 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx @@ -0,0 +1,253 @@ +/* + * 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 React from 'react'; +import { mount } from 'enzyme'; +import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; +import { isNotOperator, isOperator } from '@kbn/securitysolution-list-utils'; + +import { OperatorComponent } from '.'; +import { getField } from '../fields/index.mock'; + +describe('operator', () => { + test('it renders disabled if "isDisabled" is true', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"] input`).prop('disabled') + ).toBeTruthy(); + }); + + test('it renders loading if "isLoading" is true', () => { + const wrapper = mount( + + ); + wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"] button`).at(0).simulate('click'); + expect( + wrapper + .find(`EuiComboBoxOptionsList[data-test-subj="operatorAutocompleteComboBox-optionsList"]`) + .prop('isLoading') + ).toBeTruthy(); + }); + + test('it allows user to clear values if "isClearable" is true', () => { + const wrapper = mount( + + ); + + expect(wrapper.find(`button[data-test-subj="comboBoxClearButton"]`).exists()).toBeTruthy(); + }); + + test('it displays "operatorOptions" if param is passed in with items', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') + ).toEqual([{ label: 'is not' }]); + }); + + test('it does not display "operatorOptions" if param is passed in with no items', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') + ).toEqual([ + { + label: 'is', + }, + { + label: 'is not', + }, + { + label: 'is one of', + }, + { + label: 'is not one of', + }, + { + label: 'exists', + }, + { + label: 'does not exist', + }, + { + label: 'is in list', + }, + { + label: 'is not in list', + }, + { + label: 'matches', + }, + { + label: 'does not match', + }, + ]); + }); + + test('it correctly displays selected operator', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(0).props().value + ).toEqual('is'); + }); + + test('it only displays subset of operators if field type is nested', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') + ).toEqual([{ label: 'is' }]); + }); + + test('it only displays subset of operators if field type is boolean', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') + ).toEqual([ + { label: 'is' }, + { label: 'is not' }, + { label: 'exists' }, + { label: 'does not exist' }, + ]); + }); + + test('it only displays subset of operators if field name is "file.path.text"', () => { + const wrapper = mount( + + ); + + expect( + wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"]`).at(0).prop('options') + ).toEqual([ + { label: 'is' }, + { label: 'is not' }, + { label: 'is one of' }, + { label: 'is not one of' }, + { label: 'matches' }, + { label: 'does not match' }, + ]); + }); + + test('it invokes "onChange" when option selected', () => { + const mockOnChange = jest.fn(); + const wrapper = mount( + + ); + + ( + wrapper.find(EuiComboBox).props() as unknown as { + onChange: (a: EuiComboBoxOptionOption[]) => void; + } + ).onChange([{ label: 'is not' }]); + + expect(mockOnChange).toHaveBeenCalledWith([ + { message: 'is not', operator: 'excluded', type: 'match', value: 'is_not' }, + ]); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/operator/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/operator/index.tsx new file mode 100644 index 0000000000000..6c91f7e70b94b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/operator/index.tsx @@ -0,0 +1,99 @@ +/* + * 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 React, { useCallback, useMemo } from 'react'; +import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; +import { OperatorOption } from '@kbn/securitysolution-list-utils'; +import { DataViewFieldBase } from '@kbn/es-query'; + +import { getOperators } from '../get_operators'; +import { + getGenericComboBoxProps, + GetGenericComboBoxPropsReturn, +} from '../get_generic_combo_box_props'; + +const AS_PLAIN_TEXT = { asPlainText: true }; + +interface OperatorState { + isClearable: boolean; + isDisabled: boolean; + isLoading: boolean; + onChange: (arg: OperatorOption[]) => void; + operator: OperatorOption; + operatorInputWidth?: number; + operatorOptions?: OperatorOption[]; + placeholder: string; + selectedField: DataViewFieldBase | undefined; + 'aria-label'?: string; +} + +export const OperatorComponent: React.FC = ({ + isClearable = false, + isDisabled = false, + isLoading = false, + onChange, + operator, + operatorOptions, + operatorInputWidth = 150, + placeholder, + selectedField, + 'aria-label': ariaLabel, +}): JSX.Element => { + const getLabel = useCallback(({ message }: OperatorOption): string => message, []); + const optionsMemo = useMemo( + (): OperatorOption[] => + operatorOptions != null && operatorOptions.length > 0 + ? operatorOptions + : getOperators(selectedField), + [operatorOptions, selectedField] + ); + const selectedOptionsMemo = useMemo( + (): OperatorOption[] => (operator ? [operator] : []), + [operator] + ); + const { comboOptions, labels, selectedComboOptions } = useMemo( + (): GetGenericComboBoxPropsReturn => + getGenericComboBoxProps({ + getLabel, + options: optionsMemo, + selectedOptions: selectedOptionsMemo, + }), + [optionsMemo, selectedOptionsMemo, getLabel] + ); + + const handleValuesChange = useCallback( + (newOptions: EuiComboBoxOptionOption[]): void => { + const newValues: OperatorOption[] = newOptions.map( + ({ label }) => optionsMemo[labels.indexOf(label)] + ); + onChange(newValues); + }, + [labels, onChange, optionsMemo] + ); + + const inputWidth = useMemo(() => { + return { width: `${operatorInputWidth}px` }; + }, [operatorInputWidth]); + + return ( + + ); +}; + +OperatorComponent.displayName = 'Operator'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.test.ts new file mode 100644 index 0000000000000..d0571d157ec2b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.test.ts @@ -0,0 +1,29 @@ +/* + * 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 { paramContainsSpace } from '.'; + +describe('param_contains_space', () => { + test('should return true if leading spaces were found', () => { + expect(paramContainsSpace(' test')).toBeTruthy(); + }); + test('should return true if trailing spaces were found', () => { + expect(paramContainsSpace('test ')).toBeTruthy(); + }); + test('should return true if both trailing and leading spaces were found', () => { + expect(paramContainsSpace(' test ')).toBeTruthy(); + }); + test('should return true if tabs was found', () => { + expect(paramContainsSpace('\ttest')).toBeTruthy(); + }); + test('should return false if no spaces were found', () => { + expect(paramContainsSpace('test test')).toBeFalsy(); + }); + test('should return false if param is falsy', () => { + expect(paramContainsSpace('')).toBeFalsy(); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.ts new file mode 100644 index 0000000000000..3d7bb99ae3d05 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_contains_space/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export const paramContainsSpace = (param: string) => param && param.trim().length !== param.length; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.test.ts new file mode 100644 index 0000000000000..f93ad28eb4ad2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.test.ts @@ -0,0 +1,105 @@ +/* + * 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 { paramIsValid } from '.'; +import { getField } from '../fields/index.mock'; +import * as i18n from '../translations'; +import moment from 'moment'; + +describe('params_is_valid', () => { + beforeEach(() => { + // Disable momentJS deprecation warning and it looks like it is not typed either so + // we have to disable the type as well and cannot extend it easily. + ( + moment as unknown as { + suppressDeprecationWarnings: boolean; + } + ).suppressDeprecationWarnings = true; + }); + + afterEach(() => { + // Re-enable momentJS deprecation warning and it looks like it is not typed either so + // we have to disable the type as well and cannot extend it easily. + ( + moment as unknown as { + suppressDeprecationWarnings: boolean; + } + ).suppressDeprecationWarnings = false; + }); + + test('returns no errors if no field has been selected', () => { + const isValid = paramIsValid('', undefined, true, false); + + expect(isValid).toBeUndefined(); + }); + + test('returns error string if user has touched a required input and left empty', () => { + const isValid = paramIsValid(undefined, getField('@timestamp'), true, true); + + expect(isValid).toEqual(i18n.FIELD_REQUIRED_ERR); + }); + + test('returns no errors if required input is empty but user has not yet touched it', () => { + const isValid = paramIsValid(undefined, getField('@timestamp'), true, false); + + expect(isValid).toBeUndefined(); + }); + + test('returns no errors if user has touched an input that is not required and left empty', () => { + const isValid = paramIsValid(undefined, getField('@timestamp'), false, true); + + expect(isValid).toBeUndefined(); + }); + + test('returns no errors if user has touched an input that is not required and left empty string', () => { + const isValid = paramIsValid('', getField('@timestamp'), false, true); + + expect(isValid).toBeUndefined(); + }); + + test('returns no errors if field is of type date and value is valid', () => { + const isValid = paramIsValid('1994-11-05T08:15:30-05:00', getField('@timestamp'), false, true); + + expect(isValid).toBeUndefined(); + }); + + test('returns errors if filed is of type date and value is not valid', () => { + const isValid = paramIsValid('1593478826', getField('@timestamp'), false, true); + + expect(isValid).toEqual(i18n.DATE_ERR); + }); + + test('returns no errors if field is of type number and value is an integer', () => { + const isValid = paramIsValid('4', getField('bytes'), true, true); + + expect(isValid).toBeUndefined(); + }); + + test('returns no errors if field is of type number and value is a float', () => { + const isValid = paramIsValid('4.3', getField('bytes'), true, true); + + expect(isValid).toBeUndefined(); + }); + + test('returns no errors if field is of type number and value is a long', () => { + const isValid = paramIsValid('-9223372036854775808', getField('bytes'), true, true); + + expect(isValid).toBeUndefined(); + }); + + test('returns errors if field is of type number and value is "hello"', () => { + const isValid = paramIsValid('hello', getField('bytes'), true, true); + + expect(isValid).toEqual(i18n.NUMBER_ERR); + }); + + test('returns errors if field is of type number and value is "123abc"', () => { + const isValid = paramIsValid('123abc', getField('bytes'), true, true); + + expect(isValid).toEqual(i18n.NUMBER_ERR); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts new file mode 100644 index 0000000000000..3d091b7a9b21f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/param_is_valid/index.ts @@ -0,0 +1,48 @@ +/* + * 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 dateMath from '@kbn/datemath'; +import { DataViewFieldBase } from '@kbn/es-query'; +import { checkEmptyValue } from '../check_empty_value'; + +import * as i18n from '../translations'; + +/** + * Very basic validation for values + * @param param the value being checked + * @param field the selected field + * @param isRequired whether or not an empty value is allowed + * @param touched has field been touched by user + * @returns undefined if valid, string with error message if invalid + */ +export const paramIsValid = ( + param: string | undefined, + field: DataViewFieldBase | undefined, + isRequired: boolean, + touched: boolean +): string | undefined => { + if (field == null) { + return undefined; + } + + const emptyValueError = checkEmptyValue(param, field, isRequired, touched); + if (emptyValueError !== null) { + return emptyValueError; + } + + switch (field.type) { + case 'date': + const moment = dateMath.parse(param ?? ''); + const isDate = Boolean(moment && moment.isValid()); + return isDate ? undefined : i18n.DATE_ERR; + case 'number': + const isNum = param != null && param.trim() !== '' && !isNaN(+param); + return isNum ? undefined : i18n.NUMBER_ERR; + default: + return undefined; + } +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/translations/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/translations/index.ts new file mode 100644 index 0000000000000..51790e96ba682 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/translations/index.ts @@ -0,0 +1,79 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const LOADING = i18n.translate('autocomplete.loadingDescription', { + defaultMessage: 'Loading...', +}); + +export const SELECT_FIELD_FIRST = i18n.translate('autocomplete.selectField', { + defaultMessage: 'Please select a field first...', +}); + +export const FIELD_REQUIRED_ERR = i18n.translate('autocomplete.fieldRequiredError', { + defaultMessage: 'Value cannot be empty', +}); + +export const NUMBER_ERR = i18n.translate('autocomplete.invalidNumberError', { + defaultMessage: 'Not a valid number', +}); + +export const DATE_ERR = i18n.translate('autocomplete.invalidDateError', { + defaultMessage: 'Not a valid date', +}); + +export const BINARY_TYPE_NOT_SUPPORTED = i18n.translate('autocomplete.invalidBinaryType', { + defaultMessage: 'Binary fields are currently unsupported', +}); +export const FIELD_SPACE_WARNING = i18n.translate('autocomplete.fieldSpaceWarning', { + defaultMessage: "Warning: Spaces at the start or end of this value aren't being displayed.", +}); + +export const LISTS_TOOLTIP_INFO = i18n.translate('autocomplete.listsTooltipWarning', { + defaultMessage: "Lists that aren't able to be processed by this rule type will be disabled.", +}); + +export const SEE_DOCUMENTATION = i18n.translate('autocomplete.seeDocumentation', { + defaultMessage: 'See Documentation', +}); + +export const FIELD_CONFLICT_INDICES_WARNING_TITLE = i18n.translate( + 'autocomplete.conflictIndicesWarning.title', + { + defaultMessage: 'Mapping Conflict', + } +); + +export const FIELD_CONFLICT_INDICES_WARNING_DESCRIPTION = i18n.translate( + 'autocomplete.conflictIndicesWarning.description', + { + defaultMessage: + 'This field is defined as different types across the following indices or is unmapped. This can cause unexpected query results.', + } +); + +export const CONFLICT_MULTIPLE_INDEX_DESCRIPTION = (name: string, count: number): string => + i18n.translate('autocomplete.conflictIndicesWarning.index.description', { + defaultMessage: '{name} ({count} indices)', + values: { count, name }, + }); + +export const SHOW_VALUE_LIST_MODAL = i18n.translate('autocomplete.showValueListModal', { + defaultMessage: 'Show value list', +}); + +// eslint-disable-next-line import/no-default-export +export default { + LOADING, + SELECT_FIELD_FIRST, + FIELD_REQUIRED_ERR, + NUMBER_ERR, + DATE_ERR, + FIELD_SPACE_WARNING, + BINARY_TYPE_NOT_SUPPORTED, +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/type_match/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/type_match/index.test.ts new file mode 100644 index 0000000000000..74c713f63d360 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/type_match/index.test.ts @@ -0,0 +1,58 @@ +/* + * 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 { typeMatch } from '.'; + +describe('type_match', () => { + test('ip -> ip is true', () => { + expect(typeMatch('ip', 'ip')).toEqual(true); + }); + + test('keyword -> keyword is true', () => { + expect(typeMatch('keyword', 'keyword')).toEqual(true); + }); + + test('text -> text is true', () => { + expect(typeMatch('text', 'text')).toEqual(true); + }); + + test('ip_range -> ip is true', () => { + expect(typeMatch('ip_range', 'ip')).toEqual(true); + }); + + test('date_range -> date is true', () => { + expect(typeMatch('date_range', 'date')).toEqual(true); + }); + + test('double_range -> double is true', () => { + expect(typeMatch('double_range', 'double')).toEqual(true); + }); + + test('float_range -> float is true', () => { + expect(typeMatch('float_range', 'float')).toEqual(true); + }); + + test('integer_range -> integer is true', () => { + expect(typeMatch('integer_range', 'integer')).toEqual(true); + }); + + test('long_range -> long is true', () => { + expect(typeMatch('long_range', 'long')).toEqual(true); + }); + + test('ip -> date is false', () => { + expect(typeMatch('ip', 'date')).toEqual(false); + }); + + test('long -> float is false', () => { + expect(typeMatch('long', 'float')).toEqual(false); + }); + + test('integer -> long is false', () => { + expect(typeMatch('integer', 'long')).toEqual(false); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/type_match/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/type_match/index.ts new file mode 100644 index 0000000000000..0e368127b596c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/src/type_match/index.ts @@ -0,0 +1,26 @@ +/* + * 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 type { Type } from '@kbn/securitysolution-io-ts-list-types'; + +/** + * Given an input list type and a string based ES type this will match + * if they're exact or if they are compatible with a range + * @param type The type to match against the esType + * @param esType The ES type to match with + */ +export const typeMatch = (type: Type, esType: string): boolean => { + return ( + type === esType || + (type === 'ip_range' && esType === 'ip') || + (type === 'date_range' && esType === 'date') || + (type === 'double_range' && esType === 'double') || + (type === 'float_range' && esType === 'float') || + (type === 'integer_range' && esType === 'integer') || + (type === 'long_range' && esType === 'long') + ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/tsconfig.json new file mode 100644 index 0000000000000..e4f0b64736b07 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-autocomplete/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "kbn_references": [ + "@kbn/datemath", + "@kbn/es-query", + "@kbn/i18n", + "@kbn/securitysolution-io-ts-list-types", + "@kbn/securitysolution-list-hooks", + "@kbn/securitysolution-list-utils", + "@kbn/doc-links", + "@kbn/securitysolution-utils", + ], + "exclude": [ + "target/**/*", + ], +} diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/README.md similarity index 100% rename from packages/kbn-securitysolution-endpoint-exceptions-common/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.gen.ts new file mode 100644 index 0000000000000..c8e4f90c347a4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.gen.ts @@ -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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Create endpoint list API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { EndpointList } from '../model/endpoint_list_common.gen'; + +export type CreateEndpointListResponse = z.infer; +export const CreateEndpointListResponse = EndpointList; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.schema.yaml new file mode 100644 index 0000000000000..12b131e728c55 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list/create_endpoint_list.schema.yaml @@ -0,0 +1,45 @@ +openapi: 3.0.0 +info: + title: Create endpoint list API endpoint + version: '2023-10-31' +paths: + /api/endpoint_list: + post: + x-labels: [serverless, ess] + x-codegen-enabled: true + operationId: CreateEndpointList + summary: Create an endpoint exception list + description: Create an endpoint exception list, which groups endpoint exception list items. If an endpoint exception list already exists, an empty response is returned. + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/endpoint_list_common.schema.yaml#/components/schemas/EndpointList' + 400: + description: Invalid input data + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Insufficient privileges + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.gen.ts similarity index 81% rename from packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.gen.ts index ed3a60dc08f30..c4ce0697b2372 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.schema.yaml similarity index 79% rename from packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.schema.yaml index b90bee75fc073..0393fa3d943eb 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/create_endpoint_list_item/create_endpoint_list_item.schema.yaml @@ -57,29 +57,29 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Insufficient privileges content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 409: description: Endpoint list item already exists content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 500: description: Internal server error content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.gen.ts similarity index 75% rename from packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.gen.ts index 5cb5f518494ec..4f268641f93cd 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.schema.yaml new file mode 100644 index 0000000000000..fac5a12ecc5df --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/delete_endpoint_list_item/delete_endpoint_list_item.schema.yaml @@ -0,0 +1,64 @@ +openapi: 3.0.0 +info: + title: Delete endpoint list item API endpoint + version: '2023-10-31' +paths: + /api/endpoint_list/items: + delete: + x-labels: [serverless, ess] + x-codegen-enabled: true + operationId: DeleteEndpointListItem + summary: Delete an endpoint exception list item + description: Delete an endpoint exception list item using the `id` or `item_id` field. + parameters: + - name: id + in: query + required: false + description: Either `id` or `item_id` must be specified + schema: + $ref: '../../../kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemId' + - name: item_id + in: query + required: false + description: Either `id` or `item_id` must be specified + schema: + $ref: '../../../kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemHumanId' + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/endpoint_list_common.schema.yaml#/components/schemas/EndpointListItem' + 400: + description: Invalid input data + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Insufficient privileges + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: Endpoint list item not found + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.gen.ts similarity index 83% rename from packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.gen.ts index a830572c7b503..5b1e10d9bb04b 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.schema.yaml new file mode 100644 index 0000000000000..35f565bfa27ff --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/find_endpoint_list_item/find_endpoint_list_item.schema.yaml @@ -0,0 +1,113 @@ +openapi: 3.0.0 +info: + title: Find endpoint list items API endpoint + version: '2023-10-31' +paths: + /api/endpoint_list/items/_find: + get: + x-labels: [serverless, ess] + x-codegen-enabled: true + operationId: FindEndpointListItems + summary: Get endpoint exception list items + description: Get a list of all endpoint exception list items. + parameters: + - name: filter + in: query + required: false + description: | + Filters the returned results according to the value of the specified field, + using the `:` syntax. + schema: + $ref: '#/components/schemas/FindEndpointListItemsFilter' + - name: page + in: query + required: false + description: The page number to return + schema: + type: integer + minimum: 0 + - name: per_page + in: query + required: false + description: The number of exception list items to return per page + schema: + type: integer + minimum: 0 + - name: sort_field + in: query + required: false + description: Determines which field is used to sort the results + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + - name: sort_order + in: query + required: false + description: Determines the sort order, which can be `desc` or `asc` + schema: + type: string + enum: [desc, asc] + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '../model/endpoint_list_common.schema.yaml#/components/schemas/EndpointListItem' + page: + type: integer + minimum: 0 + per_page: + type: integer + minimum: 0 + total: + type: integer + minimum: 0 + pit: + type: string + required: + - data + - page + - per_page + - total + 400: + description: Invalid input data + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Insufficient privileges + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: Endpoint list not found + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + FindEndpointListItemsFilter: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/index.ts new file mode 100644 index 0000000000000..912af19448e44 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './create_endpoint_list/create_endpoint_list.gen'; +export * from './create_endpoint_list_item/create_endpoint_list_item.gen'; +export * from './read_endpoint_list_item/read_endpoint_list_item.gen'; +export * from './update_endpoint_list_item/update_endpoint_list_item.gen'; +export * from './delete_endpoint_list_item/delete_endpoint_list_item.gen'; +export * from './find_endpoint_list_item/find_endpoint_list_item.gen'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.gen.ts new file mode 100644 index 0000000000000..a68abd53c11c4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.gen.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Common Exception List Attributes + * version: not applicable + */ + +import { z } from '@kbn/zod'; + +import { + ExceptionList, + ExceptionListItem, +} from '@kbn/securitysolution-exceptions-common/api/model/exception_list_common.gen'; + +export type EndpointList = z.infer; +export const EndpointList = z.union([ExceptionList, z.object({}).strict()]); + +export type EndpointListItem = z.infer; +export const EndpointListItem = ExceptionListItem; diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.schema.yaml similarity index 100% rename from packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/model/endpoint_list_common.schema.yaml diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.gen.ts similarity index 75% rename from packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.gen.ts index 4a9c335b395bc..e2dc38450bbbd 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.schema.yaml new file mode 100644 index 0000000000000..45f0c384c7f09 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/read_endpoint_list_item/read_endpoint_list_item.schema.yaml @@ -0,0 +1,66 @@ +openapi: 3.0.0 +info: + title: Read endpoint list item API endpoint + version: '2023-10-31' +paths: + /api/endpoint_list/items: + get: + x-labels: [serverless, ess] + x-codegen-enabled: true + operationId: ReadEndpointListItem + summary: Get an endpoint exception list item + description: Get the details of an endpoint exception list item using the `id` or `item_id` field. + parameters: + - name: id + in: query + required: false + description: Either `id` or `item_id` must be specified + schema: + $ref: '../../../kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemId' + - name: item_id + in: query + required: false + description: Either `id` or `item_id` must be specified + schema: + $ref: '../../../kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemHumanId' + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '../model/endpoint_list_common.schema.yaml#/components/schemas/EndpointListItem' + 400: + description: Invalid input data + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Insufficient privileges + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: Endpoint list item not found + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.gen.ts similarity index 83% rename from packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.gen.ts index 0a235ca2ff896..ec86992d58b7b 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.schema.yaml similarity index 80% rename from packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.schema.yaml index 679000674c7b2..cd4cbf0c11d5e 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/api/update_endpoint_list_item/update_endpoint_list_item.schema.yaml @@ -62,29 +62,29 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Insufficient privileges content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 404: description: Endpoint list item not found content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 500: description: Internal server error content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml similarity index 100% rename from packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml similarity index 100% rename from packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-endpoint-exceptions-common/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/package.json new file mode 100644 index 0000000000000..39e6232e4e0f5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/package.json @@ -0,0 +1,11 @@ +{ + "description": "OpenAPI Endpoint Exceptions Common", + "license": "Elastic License 2.0", + "name": "@kbn/securitysolution-endpoint-exceptions-common", + "private": true, + "version": "1.0.0", + "scripts": { + "openapi:generate": "node scripts/openapi_generate", + "openapi:bundle": "node scripts/openapi_bundle" + } +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js new file mode 100644 index 0000000000000..c54e162b6462e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js @@ -0,0 +1,65 @@ +/* + * 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. + */ + +require('../../../../../../src/setup_node_env'); +// eslint-disable-next-line import/no-nodejs-modules +const { join, resolve } = require('path'); +const { bundle } = require('@kbn/openapi-bundler'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/serverless/security_solution_endpoint_exceptions_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['serverless'], + prototypeDocument: { + info: { + title: 'Security Endpoint Exceptions API (Elastic Cloud Serverless)', + description: 'Endpoint Exceptions API allow you to manage Endpoint lists.', + }, + tags: [ + { + name: 'Security Endpoint Exceptions API', + 'x-displayName': 'Security endpoint exceptions', + description: + "Endpoint Exceptions API allows you to manage detection rule endpoint exceptions to prevent a rule from generating an alert from incoming events even when the rule's other criteria are met.", + }, + ], + }, + }, + }); + + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/ess/security_solution_endpoint_exceptions_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['ess'], + prototypeDocument: { + info: { + title: 'Security Endpoint Exceptions API (Elastic Cloud and self-hosted)', + description: 'Endpoint Exceptions API allow you to manage Endpoint lists.', + }, + tags: [ + { + name: 'Security Endpoint Exceptions API', + 'x-displayName': 'Security endpoint exceptions', + description: + "Endpoint Exceptions API allows you to manage detection rule endpoint exceptions to prevent a rule from generating an alert from incoming events even when the rule's other criteria are met.", + }, + ], + }, + }, + }); +})(); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_generate.js b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_generate.js new file mode 100644 index 0000000000000..9a303c4f74bef --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_generate.js @@ -0,0 +1,37 @@ +/* + * 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. + */ + +require('../../../../../../src/setup_node_env'); +// eslint-disable-next-line import/no-nodejs-modules +const { join, resolve } = require('path'); +const { generate } = require('@kbn/openapi-generator'); +const { REPO_ROOT } = require('@kbn/repo-info'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await generate({ + title: 'OpenAPI Endpoint Exceptions API Schemas', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'zod_operation_schema', + }); + + await generate({ + title: 'Endpoint Exceptions API client for tests', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'api_client_supertest', + skipLinting: true, + bundle: { + outFile: join( + REPO_ROOT, + 'x-pack/test/api_integration/services/security_solution_endpoint_exceptions_api.gen.ts' + ), + }, + }); +})(); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/tsconfig.json new file mode 100644 index 0000000000000..38f2843b03ad7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "exclude": ["target/**/*"], + "extends": "../../../../../tsconfig.base.json", + "include": ["**/*.ts"], + "kbn_references": [ + "@kbn/securitysolution-exceptions-common", + "@kbn/openapi-common", + "@kbn/zod", + ] +} diff --git a/packages/kbn-securitysolution-exception-list-components/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/README.md similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/index.ts new file mode 100644 index 0000000000000..40277892f1f79 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export * from './src/search_bar'; +export * from './src/empty_viewer_state'; +export * from './src/pagination/pagination'; +// export * from './src/exceptions_utility/exceptions_utility'; +export * from './src/exception_items'; +export * from './src/exception_item_card'; +export * from './src/value_with_space_warning'; +export * from './src/types'; +export * from './src/list_header'; +export * from './src/header_menu'; +export * from './src/generate_linked_rules_menu_item'; +export * from './src/wildcard_with_wrong_operator_callout'; +export * from './src/partial_code_signature_callout'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/jest.config.js b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/jest.config.js new file mode 100644 index 0000000000000..d9a562b21e875 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/jest.config.js @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: [ + '/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components', + ], + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/**/*.{ts,tsx}', + '!/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/**/*.test', + '!/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/**/types/*', + '!/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/**/*.type', + '!/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/**/*.styles', + '!/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/**/mocks/*', + '!/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/**/*.config', + '!/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/**/translations', + '!/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/**/types/*', + ], + setupFilesAfterEnv: [ + '/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/setup_test.ts', + ], +}; diff --git a/packages/kbn-securitysolution-exception-list-components/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/package.json new file mode 100644 index 0000000000000..f9246cb9353d0 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/securitysolution-exception-list-components", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0", + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/setup_test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/setup_test.ts new file mode 100644 index 0000000000000..72e0edd0d07f7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/setup_test.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +// eslint-disable-next-line import/no-extraneous-dependencies +import '@testing-library/jest-dom'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/assets/images/illustration_product_no_results_magnifying_glass.svg b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/assets/images/illustration_product_no_results_magnifying_glass.svg similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/assets/images/illustration_product_no_results_magnifying_glass.svg rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/assets/images/illustration_product_no_results_magnifying_glass.svg diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/custom.d.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/custom.d.ts new file mode 100644 index 0000000000000..18dda6a910031 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/custom.d.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +declare module '*.svg' { + const content: string; + // eslint-disable-next-line import/no-default-export + export default content; +} diff --git a/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx similarity index 93% rename from packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx index 1b711185c526c..7df3f732711a0 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/empty_viewer_state.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/index.tsx new file mode 100644 index 0000000000000..2e489cb5dca97 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/empty_viewer_state/index.tsx @@ -0,0 +1,133 @@ +/* + * 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 React, { useMemo } from 'react'; +import type { FC } from 'react'; +import { css } from '@emotion/react'; +import { + EuiSkeletonText, + EuiImage, + EuiEmptyPrompt, + EuiButton, + useEuiTheme, + EuiPanel, +} from '@elastic/eui'; +import type { ExpressionColor } from '@elastic/eui/src/components/expression/expression'; +import type { EuiFacetGroupLayout } from '@elastic/eui/src/components/facet/facet_group'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { ListTypeText, ViewerStatus } from '../types'; +import * as i18n from '../translations'; +import illustration from '../assets/images/illustration_product_no_results_magnifying_glass.svg'; + +interface EmptyViewerStateProps { + title?: string; + body?: string; + buttonText?: string; + listType?: ListTypeText; + isReadOnly: boolean; + viewerStatus: ViewerStatus; + onEmptyButtonStateClick?: () => void | null; +} + +const panelCss = css` + margin: ${euiThemeVars.euiSizeL} 0; + padding: ${euiThemeVars.euiSizeL} 0; +`; +const EmptyViewerStateComponent: FC = ({ + title, + body, + buttonText, + listType, + isReadOnly, + viewerStatus, + onEmptyButtonStateClick, +}) => { + const { euiTheme } = useEuiTheme(); + + const euiEmptyPromptProps = useMemo(() => { + switch (viewerStatus) { + case ViewerStatus.ERROR: { + return { + color: 'danger' as ExpressionColor, + iconType: 'error', + title: ( +

{title || i18n.EMPTY_VIEWER_STATE_ERROR_TITLE}

+ ), + body:

{body || i18n.EMPTY_VIEWER_STATE_ERROR_BODY}

, + 'data-test-subj': 'errorViewerState', + }; + } + case ViewerStatus.EMPTY: + return { + color: 'subdued' as ExpressionColor, + iconType: 'plusInCircle', + iconColor: euiTheme.colors.darkestShade, + title: ( +

{title || i18n.EMPTY_VIEWER_STATE_EMPTY_TITLE}

+ ), + body:

{body || i18n.EMPTY_VIEWER_STATE_EMPTY_BODY}

, + 'data-test-subj': 'emptyViewerState', + actions: [ + + {buttonText || i18n.EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON(listType || 'rule')} + , + ], + }; + case ViewerStatus.EMPTY_SEARCH: + return { + color: 'plain' as ExpressionColor, + layout: 'horizontal' as EuiFacetGroupLayout, + hasBorder: true, + hasShadow: false, + icon: , + title: ( +

+ {title || i18n.EMPTY_VIEWER_STATE_EMPTY_SEARCH_TITLE} +

+ ), + body: ( +

+ {body || i18n.EMPTY_VIEWER_STATE_EMPTY_SEARCH_BODY} +

+ ), + 'data-test-subj': 'emptySearchViewerState', + }; + } + }, [ + viewerStatus, + euiTheme.colors.darkestShade, + title, + body, + onEmptyButtonStateClick, + isReadOnly, + buttonText, + listType, + ]); + + return ( + + + + + + ); +}; + +export const EmptyViewerState = React.memo(EmptyViewerStateComponent); + +EmptyViewerState.displayName = 'EmptyViewerState'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.test.tsx similarity index 83% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.test.tsx index c8c8e92cd6c70..caf989efcc9ec 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/comments.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx new file mode 100644 index 0000000000000..76ef48fba0a90 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/index.tsx @@ -0,0 +1,48 @@ +/* + * 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 React, { memo } from 'react'; +import type { EuiCommentProps } from '@elastic/eui'; +import { EuiAccordion, EuiCommentList, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import * as i18n from '../translations'; + +const accordionCss = css` + color: ${euiThemeVars.euiColorPrimary}; +`; + +export interface ExceptionItemCardCommentsProps { + comments: EuiCommentProps[]; + dataTestSubj?: string; +} + +export const ExceptionItemCardComments = memo( + ({ comments, dataTestSubj }) => { + if (!comments.length) return null; + return ( + + + {i18n.exceptionItemCardCommentsAccordion(comments.length)} + + } + arrowDisplay="none" + data-test-subj="exceptionItemCardComments" + > + + + + + + ); + } +); + +ExceptionItemCardComments.displayName = 'ExceptionItemCardComments'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.config.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.config.ts similarity index 77% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.config.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.config.ts index fdb545dc2c031..0c826f40f0224 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.config.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.config.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { ListOperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.styles.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.styles.tsx new file mode 100644 index 0000000000000..043e2e2e44850 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.styles.tsx @@ -0,0 +1,36 @@ +/* + * 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 { cx } from '@emotion/css'; +import { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; + +// TODO check font Roboto Mono +export const nestedGroupSpaceCss = css` + margin-left: ${euiThemeVars.euiSizeXL}; + margin-bottom: ${euiThemeVars.euiSizeXS}; + padding-top: ${euiThemeVars.euiSizeXS}; +`; + +export const borderCss = cx( + 'eui-xScroll', + ` + border: 1px; + border-color: #d3dae6; + border-style: solid; +` +); + +export const valueContainerCss = css` + display: flex; + align-items: center; + margin-left: ${euiThemeVars.euiSizeS}; +`; +export const expressionContainerCss = css` + display: flex; + align-items: center; +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx similarity index 96% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx index e19327226de21..6cd3ee06d203a 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/conditions.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { render } from '@testing-library/react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/__snapshots__/entry_content.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/__snapshots__/entry_content.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/__snapshots__/entry_content.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/__snapshots__/entry_content.test.tsx.snap diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.test.tsx similarity index 93% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.test.tsx index e49d18ec78c49..07de278ace7b3 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { ListOperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx similarity index 85% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx index 2fa113e5a612a..aeca92d4d0031 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.helper.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React, { ElementType } from 'react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.test.tsx similarity index 83% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.test.tsx index 7eb141493ef40..bed784f46b878 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/entry_content.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/index.tsx new file mode 100644 index 0000000000000..7f75694b16d34 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/entry_content/index.tsx @@ -0,0 +1,81 @@ +/* + * 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 React, { ElementType, FC, memo } from 'react'; +import { EuiExpression, EuiToken, EuiFlexGroup } from '@elastic/eui'; +import { ListOperatorTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import { + nestedGroupSpaceCss, + valueContainerCss, + expressionContainerCss, +} from '../conditions.styles'; +import type { Entry } from '../types'; +import * as i18n from '../../translations'; +import { getValue, getValueExpression } from './entry_content.helper'; + +interface EntryContentProps { + entry: Entry; + index: number; + isNestedEntry?: boolean; + dataTestSubj?: string; + showValueListModal: ElementType; +} + +export const EntryContent: FC = memo( + ({ entry, index, isNestedEntry = false, dataTestSubj, showValueListModal }) => { + const { field, type } = entry; + const value = getValue(entry); + const operator = 'operator' in entry ? entry.operator : ''; + + const entryKey = `${field}${type}${value}${index}`; + return ( +
+
+ {isNestedEntry ? ( + + + +
+ + {getValueExpression( + type as ListOperatorTypeEnum, + operator, + value, + showValueListModal + )} +
+
+ ) : ( + <> + + + {getValueExpression( + type as ListOperatorTypeEnum, + operator, + value, + showValueListModal + )} + + )} +
+
+ ); + } +); +EntryContent.displayName = 'EntryContent'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx new file mode 100644 index 0000000000000..804af918e4f16 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/index.tsx @@ -0,0 +1,57 @@ +/* + * 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 React, { memo } from 'react'; +import { EuiPanel } from '@elastic/eui'; + +import { borderCss } from './conditions.styles'; +import { EntryContent } from './entry_content'; +import { OsCondition } from './os_conditions'; +import type { CriteriaConditionsProps, Entry } from './types'; + +export const ExceptionItemCardConditions = memo( + ({ os, entries, dataTestSubj, showValueListModal }) => { + return ( + + {os?.length ? : null} + {entries.map((entry: Entry, index: number) => { + const nestedEntries = 'entries' in entry ? entry.entries : []; + return ( +
+ + {nestedEntries?.length + ? nestedEntries.map((nestedEntry: Entry, nestedIndex: number) => ( + + )) + : null} +
+ ); + })} +
+ ); + } +); +ExceptionItemCardConditions.displayName = 'ExceptionItemCardConditions'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/__snapshots__/os_conditions.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/__snapshots__/os_conditions.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/__snapshots__/os_conditions.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/__snapshots__/os_conditions.test.tsx.snap diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/index.tsx new file mode 100644 index 0000000000000..3a2dded6ce2ba --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/index.tsx @@ -0,0 +1,37 @@ +/* + * 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 React, { memo, useMemo } from 'react'; +import { EuiExpression } from '@elastic/eui'; + +import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { OS_LABELS } from '../conditions.config'; +import * as i18n from '../../translations'; + +export interface OsConditionsProps { + dataTestSubj?: string; + os: ExceptionListItemSchema['os_types']; +} + +export const OsCondition = memo(({ os, dataTestSubj }) => { + const osLabel = useMemo(() => { + return os.map((osValue) => OS_LABELS[osValue] ?? osValue).join(', '); + }, [os]); + return osLabel ? ( +
+ + + + +
+ ) : null; +}); +OsCondition.displayName = 'OsCondition'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.test.tsx similarity index 82% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.test.tsx index 3aea8d5ed0065..a3575c1845227 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/os_conditions/os_conditions.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; @@ -35,6 +33,7 @@ describe('OsCondition', () => { expect(wrapper.container).toMatchSnapshot(); }); it('should return any os sent', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const wrapper = render(); expect(wrapper.getByTestId('osLabel')).toHaveTextContent(i18n.CONDITION_OS); expect(wrapper.getByTestId('osValue')).toHaveTextContent( diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/types.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/types.ts new file mode 100644 index 0000000000000..a69a0f16c1d7b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/conditions/types.ts @@ -0,0 +1,33 @@ +/* + * 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 type { + EntryExists, + EntryList, + EntryMatch, + EntryMatchAny, + EntryMatchWildcard, + EntryNested, + ExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { ElementType } from 'react'; + +export type Entry = + | EntryExists + | EntryList + | EntryMatch + | EntryMatchAny + | EntryMatchWildcard + | EntryNested; + +export type Entries = ExceptionListItemSchema['entries']; +export interface CriteriaConditionsProps { + entries: Entries; + dataTestSubj: string; + os?: ExceptionListItemSchema['os_types']; + showValueListModal: ElementType; +} diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.test.tsx similarity index 94% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.test.tsx index aeaf5755ea1da..b3f06eddec715 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx similarity index 91% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx index 44456a130687d..52d2f730b33b9 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React, { FC, ElementType } from 'react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx similarity index 81% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx index 5de4f5d729f0c..9127589b5b560 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/header.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx new file mode 100644 index 0000000000000..88eb6233a9350 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/header/index.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { HeaderMenu } from '../../header_menu'; + +export interface ExceptionItemCardHeaderProps { + item: ExceptionListItemSchema; + actions: Array<{ key: string; icon: string; label: string | boolean; onClick: () => void }>; + disableActions?: boolean; + dataTestSubj: string; +} + +export const ExceptionItemCardHeader = memo( + ({ item, actions, disableActions = false, dataTestSubj }) => { + return ( + + + +

{item.name}

+
+
+ + + +
+ ); + } +); + +ExceptionItemCardHeader.displayName = 'ExceptionItemCardHeader'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts new file mode 100644 index 0000000000000..2d2b38d288da9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +export * from './conditions'; +export * from './header'; +export * from './meta'; +export * from './comments'; +export * from './exception_item_card'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/__snapshots__/details_info.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/__snapshots__/details_info.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/__snapshots__/details_info.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/__snapshots__/details_info.test.tsx.snap diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.test.tsx new file mode 100644 index 0000000000000..3950d674a1add --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/details_info.test.tsx @@ -0,0 +1,38 @@ +/* + * 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 React from 'react'; +import { render } from '@testing-library/react'; +import { MetaInfoDetails } from '.'; + +describe('MetaInfoDetails', () => { + it('should render lastUpdate as string', () => { + const wrapper = render( + + ); + expect(wrapper.container).toMatchSnapshot(); + expect(wrapper.getByTestId('MetaInfoDetailslastUpdate')).toHaveTextContent('last update'); + }); + it('should render lastUpdate as JSX Element', () => { + const wrapper = render( + Last update value

} + lastUpdateValue="value" + /> + ); + expect(wrapper.container).toMatchSnapshot(); + expect(wrapper.getByTestId('MetaInfoDetailslastUpdate')).toHaveTextContent('Last update value'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/index.tsx new file mode 100644 index 0000000000000..209ce3b59553c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/details_info/index.tsx @@ -0,0 +1,67 @@ +/* + * 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 React, { memo } from 'react'; +import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import * as i18n from '../../translations'; + +interface MetaInfoDetailsProps { + label: string; + lastUpdate: JSX.Element | string; + lastUpdateValue?: string; + dataTestSubj?: string; +} + +const euiBadgeFontFamily = css` + font-family: ${euiThemeVars.euiFontFamily}; +`; +export const MetaInfoDetails = memo( + ({ label, lastUpdate, lastUpdateValue, dataTestSubj }) => { + return ( + + + + {label} + + + + + {lastUpdate} + + + {lastUpdateValue != null && ( + <> + + + {i18n.EXCEPTION_ITEM_CARD_META_BY} + + + + + + + {lastUpdateValue} + + + + + + )} + + ); + } +); + +MetaInfoDetails.displayName = 'MetaInfoDetails'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx new file mode 100644 index 0000000000000..8c7734ab51c99 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx @@ -0,0 +1,123 @@ +/* + * 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 React, { memo, useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import * as i18n from '../translations'; +import type { Rule } from '../../types'; +import { MetaInfoDetails } from './details_info'; +import { HeaderMenu } from '../../header_menu'; +import { generateLinkedRulesMenuItems } from '../../generate_linked_rules_menu_item'; + +const itemCss = css` + border-right: 1px solid #d3dae6; + padding: ${euiThemeVars.euiSizeS} ${euiThemeVars.euiSizeM} ${euiThemeVars.euiSizeS} 0; +`; + +export interface ExceptionItemCardMetaInfoProps { + item: ExceptionListItemSchema; + rules: Rule[]; + dataTestSubj: string; + formattedDateComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common +} + +export const ExceptionItemCardMetaInfo = memo( + ({ item, rules, dataTestSubj, securityLinkAnchorComponent, formattedDateComponent }) => { + const FormattedDateComponent = formattedDateComponent; + + const referencedLinks = useMemo( + () => + generateLinkedRulesMenuItems({ + dataTestSubj, + linkedRules: rules, + securityLinkAnchorComponent, + }), + [dataTestSubj, rules, securityLinkAnchorComponent] + ); + + const isExpired = useMemo( + () => (item.expire_time ? new Date(item.expire_time) <= new Date() : false), + [item] + ); + + return ( + + {FormattedDateComponent !== null && ( + <> + + + } + lastUpdateValue={item.created_by} + dataTestSubj={`${dataTestSubj || ''}CreatedBy`} + /> + + + + + } + lastUpdateValue={item.updated_by} + dataTestSubj={`${dataTestSubj || ''}UpdatedBy`} + /> + + {item.expire_time != null && ( + <> + + + } + dataTestSubj={`${dataTestSubj || ''}ExpireTime`} + /> + + + )} + + )} + + + + + ); + } +); +ExceptionItemCardMetaInfo.displayName = 'ExceptionItemCardMetaInfo'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx similarity index 90% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx index 10570b2637812..f7a94d9d76ff9 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/meta.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/translations.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/translations.ts new file mode 100644 index 0000000000000..9b1a64bd6cf40 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/translations.ts @@ -0,0 +1,179 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const exceptionItemCardEditButton = (listType: string) => + i18n.translate('exceptionList-components.exceptions.exceptionItem.card.editItemButton', { + values: { listType }, + defaultMessage: 'Edit {listType} exception', + }); + +export const exceptionItemCardDeleteButton = (listType: string) => + i18n.translate('exceptionList-components.exceptions.exceptionItem.card.deleteItemButton', { + values: { listType }, + defaultMessage: 'Delete {listType} exception', + }); + +export const EXCEPTION_ITEM_CARD_CREATED_LABEL = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.createdLabel', + { + defaultMessage: 'Created', + } +); + +export const EXCEPTION_ITEM_CARD_UPDATED_LABEL = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.updatedLabel', + { + defaultMessage: 'Updated', + } +); + +export const EXCEPTION_ITEM_CARD_EXPIRES_LABEL = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.expiresLabel', + { + defaultMessage: 'Expires at', + } +); + +export const EXCEPTION_ITEM_CARD_EXPIRED_LABEL = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.expiredLabel', + { + defaultMessage: 'Expired at', + } +); + +export const EXCEPTION_ITEM_CARD_META_BY = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.metaDetailsBy', + { + defaultMessage: 'by', + } +); + +export const exceptionItemCardCommentsAccordion = (comments: number) => + i18n.translate('exceptionList-components.exceptions.exceptionItem.card.showCommentsLabel', { + values: { comments }, + defaultMessage: 'Show {comments, plural, =1 {comment} other {comments}} ({comments})', + }); + +export const CONDITION_OPERATOR_TYPE_MATCH = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.matchOperator', + { + defaultMessage: 'IS', + } +); + +export const CONDITION_OPERATOR_TYPE_NOT_MATCH = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.matchOperator.not', + { + defaultMessage: 'IS NOT', + } +); + +export const CONDITION_OPERATOR_TYPE_WILDCARD_MATCHES = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.wildcardMatchesOperator', + { + defaultMessage: 'MATCHES', + } +); + +export const CONDITION_OPERATOR_TYPE_WILDCARD_DOES_NOT_MATCH = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.wildcardDoesNotMatchOperator', + { + defaultMessage: 'DOES NOT MATCH', + } +); + +export const CONDITION_OPERATOR_TYPE_NESTED = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.nestedOperator', + { + defaultMessage: 'has', + } +); + +export const CONDITION_OPERATOR_TYPE_MATCH_ANY = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.matchAnyOperator', + { + defaultMessage: 'is one of', + } +); + +export const CONDITION_OPERATOR_TYPE_NOT_MATCH_ANY = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.matchAnyOperator.not', + { + defaultMessage: 'is not one of', + } +); + +export const CONDITION_OPERATOR_TYPE_EXISTS = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.existsOperator', + { + defaultMessage: 'exists', + } +); + +export const CONDITION_OPERATOR_TYPE_DOES_NOT_EXIST = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.existsOperator.not', + { + defaultMessage: 'does not exist', + } +); + +export const CONDITION_OPERATOR_TYPE_LIST = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.listOperator', + { + defaultMessage: 'included in', + } +); + +export const CONDITION_OPERATOR_TYPE_NOT_IN_LIST = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.listOperator.not', + { + defaultMessage: 'is not included in', + } +); + +export const CONDITION_AND = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.and', + { + defaultMessage: 'AND', + } +); + +export const CONDITION_OS = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.os', + { + defaultMessage: 'OS', + } +); + +export const OS_WINDOWS = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.windows', + { + defaultMessage: 'Windows', + } +); + +export const OS_LINUX = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.linux', + { + defaultMessage: 'Linux', + } +); + +export const OS_MAC = i18n.translate( + 'exceptionList-components.exceptions.exceptionItem.card.conditions.macos', + { + defaultMessage: 'Mac', + } +); + +export const AFFECTED_RULES = (numRules: number) => + i18n.translate('exceptionList-components.exceptions.card.exceptionItem.affectedRules', { + values: { numRules }, + defaultMessage: 'Affects {numRules} {numRules, plural, =1 {rule} other {rules}}', + }); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.test.ts similarity index 90% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.test.ts index 5c04c87727147..1a144182eeed8 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.ts similarity index 86% rename from packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.ts index 2978dfb12c727..f3da4ec925955 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/use_exception_item_card.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { useCallback, useMemo } from 'react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx similarity index 96% rename from packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx index e60cff40626ff..936a58b670f52 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_items/exception_items.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx new file mode 100644 index 0000000000000..6fde321cfcb93 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/exception_items/index.tsx @@ -0,0 +1,153 @@ +/* + * 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 React, { ElementType } from 'react'; +import { css } from '@emotion/react'; +import type { FC } from 'react'; +import { EuiCommentProps, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import type { + CommentsArray, + ExceptionListItemSchema, + ExceptionListTypeEnum, +} from '@kbn/securitysolution-io-ts-list-types'; + +import { euiThemeVars } from '@kbn/ui-theme'; +import { EmptyViewerState, ExceptionItemCard, Pagination, PaginationProps } from '../..'; + +import type { + RuleReferences, + ExceptionListItemIdentifiers, + ViewerStatus, + GetExceptionItemProps, +} from '../types'; + +const exceptionItemCss = css` + margin: ${euiThemeVars.euiSize} 0; + &div:first-child { + margin: ${euiThemeVars.euiSizeXS} 0 ${euiThemeVars.euiSize}; + } +`; + +interface ExceptionItemsProps { + lastUpdated: string | number | null; + viewerStatus: ViewerStatus; + isReadOnly: boolean; + emptyViewerTitle?: string; + emptyViewerBody?: string; + emptyViewerButtonText?: string; + exceptions: ExceptionListItemSchema[]; + listType: ExceptionListTypeEnum; + ruleReferences: RuleReferences; + pagination: PaginationProps['pagination']; + editActionLabel?: string; + deleteActionLabel?: string; + dataTestSubj?: string; + securityLinkAnchorComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + formattedDateComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + exceptionsUtilityComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + getFormattedComments: (comments: CommentsArray) => EuiCommentProps[]; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + onCreateExceptionListItem?: () => void; + onDeleteException: (arg: ExceptionListItemIdentifiers) => void; + onEditExceptionItem: (item: ExceptionListItemSchema) => void; + onPaginationChange: (arg: GetExceptionItemProps) => void; + showValueListModal: ElementType; +} + +const ExceptionItemsComponent: FC = ({ + lastUpdated, + viewerStatus, + isReadOnly, + exceptions, + listType, + ruleReferences, + emptyViewerTitle, + emptyViewerBody, + emptyViewerButtonText, + pagination, + dataTestSubj, + editActionLabel, + deleteActionLabel, + securityLinkAnchorComponent, + exceptionsUtilityComponent, + formattedDateComponent, + getFormattedComments, + onPaginationChange, + onDeleteException, + onEditExceptionItem, + onCreateExceptionListItem, + showValueListModal, +}) => { + const ExceptionsUtility = exceptionsUtilityComponent; + if (!exceptions.length || viewerStatus) + return ( + + ); + const ShowValueListModal = showValueListModal; + return ( + <> + + + + + {exceptions.map((exception) => ( + + + + ))} + + + + + + ); +}; + +ExceptionItemsComponent.displayName = 'ExceptionItemsComponent'; + +export const ExceptionItems = React.memo(ExceptionItemsComponent); + +ExceptionItems.displayName = 'ExceptionsItems'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/__snapshots__/generate_linked_rules_menu_item.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/__snapshots__/generate_linked_rules_menu_item.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/__snapshots__/generate_linked_rules_menu_item.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/__snapshots__/generate_linked_rules_menu_item.test.tsx.snap diff --git a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/generate_linked_rules_menu_item.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/generate_linked_rules_menu_item.test.tsx similarity index 80% rename from packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/generate_linked_rules_menu_item.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/generate_linked_rules_menu_item.test.tsx index 01f708a0f6bdc..2bf26f551fb06 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/generate_linked_rules_menu_item.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/generate_linked_rules_menu_item.test.tsx @@ -1,15 +1,12 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { render } from '@testing-library/react'; -import { ReactElement } from 'react'; -import { ElementType } from 'react'; +import { ReactElement, ElementType } from 'react'; import { generateLinkedRulesMenuItems } from '.'; import { rules } from '../mocks/rule_references.mock'; import { @@ -45,7 +42,7 @@ describe('generateLinedRulesMenuItems', () => { leftIcon: 'check', }) as ReactElement[]; - result.map((link) => { + result.forEach((link) => { const wrapper = render(link); expect(wrapper.container).toMatchSnapshot(); expect(wrapper.getByTestId('generateLinedRulesMenuItemsTestActionItem1a2b3c')); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/index.tsx new file mode 100644 index 0000000000000..9187d0975e92a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/index.tsx @@ -0,0 +1,49 @@ +/* + * 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 React, { ElementType, ReactElement } from 'react'; +import { EuiContextMenuItem, EuiFlexGroup, EuiFlexItem, EuiIcon, IconType } from '@elastic/eui'; +import { Rule } from '../types'; +import { itemContentCss, containerCss } from './menu_link.styles'; + +interface MenuItemLinkedRulesProps { + leftIcon?: IconType; + dataTestSubj?: string; + linkedRules: Rule[]; + securityLinkAnchorComponent: ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common +} + +export const generateLinkedRulesMenuItems = ({ + dataTestSubj, + linkedRules, + securityLinkAnchorComponent, + leftIcon = '', +}: MenuItemLinkedRulesProps): ReactElement[] | null => { + if (!linkedRules.length || securityLinkAnchorComponent === null) return null; + + const SecurityLinkAnchor = securityLinkAnchorComponent; + return linkedRules.map((rule) => { + return ( + 1 ? containerCss : ''} + data-test-subj={`${dataTestSubj || ''}ActionItem${rule.id}`} + key={rule.id} + > + + {leftIcon ? ( + + + + ) : null} + + + + + + ); + }); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/menu_link.styles.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/menu_link.styles.ts new file mode 100644 index 0000000000000..886369b22e23b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/generate_linked_rules_menu_item/menu_link.styles.ts @@ -0,0 +1,18 @@ +/* + * 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 { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; + +export const containerCss = css` + border-bottom: 1px solid ${euiThemeVars.euiColorLightShade}; +`; + +export const itemContentCss = css` + color: ${euiThemeVars.euiColorPrimary}; + flex-basis: content; +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap diff --git a/packages/kbn-securitysolution-exception-list-components/src/header_menu/header_menu.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/header_menu/header_menu.test.tsx similarity index 93% rename from packages/kbn-securitysolution-exception-list-components/src/header_menu/header_menu.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/header_menu/header_menu.test.tsx index 7e14b503721b5..2869b16e3aaa2 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/header_menu/header_menu.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/header_menu/header_menu.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { createEvent, fireEvent, render } from '@testing-library/react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx new file mode 100644 index 0000000000000..bd634b5f6c361 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/header_menu/index.tsx @@ -0,0 +1,137 @@ +/* + * 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 React, { FC, ReactElement, useMemo, useState } from 'react'; +import { + EuiButtonEmpty, + EuiButtonEmptyProps, + EuiButtonIcon, + EuiContextMenuItem, + EuiContextMenuPanel, + EuiFlexGroup, + EuiPopover, + PanelPaddingSize, + PopoverAnchorPosition, +} from '@elastic/eui'; + +import { css } from '@emotion/react'; + +export interface Action { + key: string; + icon: string; + label: string | boolean; + disabled?: boolean; + onClick: (e: React.MouseEvent) => void; +} + +interface HeaderMenuComponentProps { + disableActions: boolean; + actions: Action[] | ReactElement[] | null; + text?: string; + iconType?: EuiButtonEmptyProps['iconType']; + iconSide?: EuiButtonEmptyProps['iconSide']; + dataTestSubj?: string; + emptyButton?: boolean; + useCustomActions?: boolean; + anchorPosition?: PopoverAnchorPosition; + panelPaddingSize?: PanelPaddingSize; +} + +const popoverHeightStyle = css` + max-height: 300px; + height: 100%; + overflow-x: hidden; + overflow-y: auto; +`; +const HeaderMenuComponent: FC = ({ + text, + dataTestSubj, + actions, + disableActions, + emptyButton, + useCustomActions, + iconType, + iconSide = 'left', + anchorPosition = 'downCenter', + panelPaddingSize = 's', +}) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const onAffectedRulesClick = () => setIsPopoverOpen((isOpen) => !isOpen); + const onClosePopover = () => setIsPopoverOpen(false); + + const itemActions = useMemo(() => { + if (useCustomActions || actions === null) return actions; + return (actions as Action[]).map((action) => ( + { + onClosePopover(); + if (typeof action.onClick === 'function') action.onClick(e); + }} + > + {action.label} + + )); + }, [actions, dataTestSubj, useCustomActions]); + + return ( + + + {text} + + ) : ( + + {text} + + ) + } + onClick={(e) => e.stopPropagation()} + panelPaddingSize={panelPaddingSize} + isOpen={isPopoverOpen} + closePopover={onClosePopover} + anchorPosition={anchorPosition} + data-test-subj={`${dataTestSubj || ''}Items`} + > + {!itemActions ? null : ( + + )} + + + ); +}; +HeaderMenuComponent.displayName = 'HeaderMenuComponent'; + +export const HeaderMenu = React.memo(HeaderMenuComponent); + +HeaderMenu.displayName = 'HeaderMenu'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/__snapshots__/edit_modal.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/__snapshots__/edit_modal.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/__snapshots__/edit_modal.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/__snapshots__/edit_modal.test.tsx.snap diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/edit_modal.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/edit_modal.test.tsx similarity index 93% rename from packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/edit_modal.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/edit_modal.test.tsx index 39692e35394ec..9b23afaf2089e 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/edit_modal.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/edit_modal.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/index.tsx new file mode 100644 index 0000000000000..fda87a768fd0d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/index.tsx @@ -0,0 +1,109 @@ +/* + * 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 React, { FC } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiTextArea, + EuiProgress, +} from '@elastic/eui'; +import * as i18n from '../../translations'; +import { ListDetails } from '../../types'; +import { useEditModal } from './use_edit_modal'; + +interface EditModalProps { + listDetails: ListDetails; + onSave: (newListDetails: ListDetails) => void; + onCancel: () => void; +} + +const EditModalComponent: FC = ({ listDetails, onSave, onCancel }) => { + const { error, modalFormId, newListDetails, showProgress, onBlur, onSubmit, onChange } = + useEditModal({ + listDetails, + onSave, + }); + return ( + + {showProgress && ( + + )} + + + {i18n.EXCEPTION_LIST_HEADER_EDIT_MODAL_TITLE(listDetails.name)} + + + + + + + + + + + + + + + + + + {i18n.EXCEPTION_LIST_HEADER_EDIT_MODAL_CANCEL_BUTTON} + + + + {i18n.EXCEPTION_LIST_HEADER_EDIT_MODAL_SAVE_BUTTON} + + + + ); +}; +EditModalComponent.displayName = 'EditModalComponent'; + +export const EditModal = React.memo(EditModalComponent); + +EditModal.displayName = 'EditModal'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.test.ts similarity index 81% rename from packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.test.ts index 65b532a55c834..a540fdd7704db 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { ChangeEvent, SyntheticEvent } from 'react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.ts similarity index 80% rename from packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.ts index 6977b8467b94a..38c60328ef3d2 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/edit_modal/use_edit_modal.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { useGeneratedHtmlId } from '@elastic/eui'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx new file mode 100644 index 0000000000000..a6fce88699993 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/index.tsx @@ -0,0 +1,138 @@ +/* + * 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. + */ + +/* eslint-disable react/jsx-no-literals */ + +import React from 'react'; +import type { FC } from 'react'; +import { EuiIcon, EuiPageHeader, EuiText } from '@elastic/eui'; +import * as i18n from '../translations'; +import { textCss, descriptionContainerCss, backTextCss } from './list_header.styles'; +import { MenuItems } from './menu_items'; +import { TextWithEdit } from '../text_with_edit'; +import { EditModal } from './edit_modal'; +import { ListDetails, Rule } from '../types'; +import { useExceptionListHeader } from './use_list_header'; +import { textWithEditContainerCss } from '../text_with_edit/text_with_edit.styles'; + +interface ExceptionListHeaderComponentProps { + name: string; + description?: string; + listId: string; + isReadonly: boolean; + linkedRules: Rule[]; + dataTestSubj?: string; + backOptions: BackOptions; + canUserEditList?: boolean; + securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + onEditListDetails: (listDetails: ListDetails) => void; + onDeleteList: () => void; + onManageRules: () => void; + onExportList: () => void; + onDuplicateList: () => void; +} + +export interface BackOptions { + pageId: string; + path: string; + dataTestSubj?: string; + onNavigate: (path: string) => void; +} +const ExceptionListHeaderComponent: FC = ({ + name, + description, + listId, + linkedRules, + isReadonly, + dataTestSubj, + securityLinkAnchorComponent, + backOptions, + canUserEditList = true, + onEditListDetails, + onDeleteList, + onManageRules, + onExportList, + onDuplicateList, +}) => { + const { isModalVisible, listDetails, onEdit, onSave, onCancel } = useExceptionListHeader({ + name, + description, + onEditListDetails, + }); + return ( +
+ + } + responsive + data-test-subj={`${dataTestSubj || ''}PageHeader`} + description={ +
+ +
+ {i18n.EXCEPTION_LIST_HEADER_LIST_ID}: + {listId} +
+
+ } + rightSideItems={[ + , + ]} + breadcrumbs={[ + { + text: ( +
+ + {i18n.EXCEPTION_LIST_HEADER_BREADCRUMB} +
+ ), + color: 'primary', + 'aria-current': false, + href: backOptions.path, + onClick: (e) => { + e.preventDefault(); + backOptions.onNavigate(backOptions.path); + }, + }, + ]} + /> + {isModalVisible && ( + + )} +
+ ); +}; + +ExceptionListHeaderComponent.displayName = 'ExceptionListHeaderComponent'; + +export const ExceptionListHeader = React.memo(ExceptionListHeaderComponent); + +ExceptionListHeader.displayName = 'ExceptionListHeader'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.styles.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.styles.ts new file mode 100644 index 0000000000000..7a82cd9bc2893 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.styles.ts @@ -0,0 +1,32 @@ +/* + * 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 { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; + +export const headerMenuCss = css` + border-right: 1px solid #d3dae6; + padding: ${euiThemeVars.euiSizeXS} ${euiThemeVars.euiSizeL} ${euiThemeVars.euiSizeXS} 0; +`; + +export const noLinkedRulesCss = css` + width: max-content; +`; + +export const textCss = css` + font-size: ${euiThemeVars.euiFontSize}; + color: ${euiThemeVars.euiTextSubduedColor}; + margin-left: ${euiThemeVars.euiSizeXS}; +`; +export const descriptionContainerCss = css` + margin-top: -${euiThemeVars.euiSizeL}; + margin-bottom: -${euiThemeVars.euiSizeL}; +`; + +export const backTextCss = css` + font-size: ${euiThemeVars.euiFontSizeXS}; +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.test.tsx similarity index 94% rename from packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.test.tsx index 9ceb648dfa7e1..246e880716087 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/list_header.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/index.tsx new file mode 100644 index 0000000000000..798f737be65db --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/index.tsx @@ -0,0 +1,134 @@ +/* + * 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 { EuiButton, EuiFlexGroup, EuiFlexItem, EuiTextColor } from '@elastic/eui'; +import React, { FC, useMemo } from 'react'; +import { HeaderMenu } from '../../header_menu'; +import { headerMenuCss, noLinkedRulesCss } from '../list_header.styles'; +import * as i18n from '../../translations'; +import { Rule } from '../../types'; +import { generateLinkedRulesMenuItems } from '../../generate_linked_rules_menu_item'; +interface MenuItemsProps { + isReadonly: boolean; + dataTestSubj?: string; + linkedRules: Rule[]; + canUserEditList?: boolean; + securityLinkAnchorComponent: React.ElementType; // This property needs to be removed to avoid the Prop Drilling, once we move all the common components from x-pack/security-solution/common + onDeleteList: () => void; + onManageRules: () => void; + onExportList: () => void; + onDuplicateList: () => void; +} + +const MenuItemsComponent: FC = ({ + dataTestSubj, + linkedRules, + securityLinkAnchorComponent, + isReadonly, + canUserEditList = true, + onDeleteList, + onManageRules, + onExportList, + onDuplicateList, +}) => { + const referencedLinks = useMemo( + () => + generateLinkedRulesMenuItems({ + leftIcon: 'check', + dataTestSubj, + linkedRules, + securityLinkAnchorComponent, + }), + [dataTestSubj, linkedRules, securityLinkAnchorComponent] + ); + return ( + + + {linkedRules.length ? ( + + ) : ( + + {i18n.EXCEPTION_LIST_HEADER_LINKED_RULES(linkedRules.length)} + + )} + + + {canUserEditList && ( + + { + if (typeof onManageRules === 'function') onManageRules(); + }} + > + {i18n.EXCEPTION_LIST_HEADER_LINK_RULES_BUTTON} + + + )} + + { + if (typeof onExportList === 'function') onExportList(); + }, + }, + { + key: '2', + icon: 'copy', + label: i18n.EXCEPTION_LIST_HEADER_DUPLICATE_ACTION, + onClick: () => { + if (typeof onDuplicateList === 'function') onDuplicateList(); + }, + disabled: !canUserEditList, + }, + { + key: '3', + icon: 'trash', + label: i18n.EXCEPTION_LIST_HEADER_DELETE_ACTION, + onClick: () => { + if (typeof onDeleteList === 'function') onDeleteList(); + }, + disabled: !canUserEditList, + }, + ]} + disableActions={isReadonly} + anchorPosition="downCenter" + /> + + + ); +}; + +MenuItemsComponent.displayName = 'MenuItemsComponent'; + +export const MenuItems = React.memo(MenuItemsComponent); + +MenuItems.displayName = 'MenuItems'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/menu_items.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/menu_items.test.tsx similarity index 94% rename from packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/menu_items.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/menu_items.test.tsx index 16072bab295ab..8fdf6519cf448 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/menu_items.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/menu_items.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { fireEvent, render } from '@testing-library/react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.test.ts similarity index 86% rename from packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.test.ts index e16681d2b184b..a49ef8f6f560c 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { waitFor, renderHook, act } from '@testing-library/react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.ts new file mode 100644 index 0000000000000..cda4bf346a203 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/list_header/use_list_header.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useState } from 'react'; +import { ListDetails } from '../types'; + +interface UseExceptionListHeaderProps { + name: string; + description?: string; + onEditListDetails: (listDetails: ListDetails) => void; +} +export const useExceptionListHeader = ({ + name, + description, + onEditListDetails, +}: UseExceptionListHeaderProps) => { + const [isModalVisible, setIsModalVisible] = useState(false); + const [listDetails, setListDetails] = useState({ name, description }); + const onEdit = () => { + setIsModalVisible(true); + }; + const onSave = (newListDetails: ListDetails) => { + setListDetails(newListDetails); + if (typeof onEditListDetails === 'function') onEditListDetails(newListDetails); + setTimeout(() => { + setIsModalVisible(false); + }, 200); + }; + const onCancel = () => { + setIsModalVisible(false); + }; + + return { + isModalVisible, + listDetails, + onEdit, + onSave, + onCancel, + }; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/comments.mock.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/comments.mock.tsx new file mode 100644 index 0000000000000..02767cfb979de --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/comments.mock.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { Comment, CommentsArray } from '@kbn/securitysolution-io-ts-list-types'; + +export const getCommentsMock = (): Comment => ({ + comment: 'some old comment', + created_at: '2020-04-20T15:25:31.830Z', + created_by: 'some user', + id: 'uuid_here', +}); + +export const getCommentsArrayMock = (): CommentsArray => [getCommentsMock(), getCommentsMock()]; + +export const mockGetFormattedComments = () => + getCommentsArrayMock().map((comment) => ({ + username: comment.created_by, + children:

{comment.comment}

, + })); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/entry.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/entry.mock.ts new file mode 100644 index 0000000000000..34a4e98cf981a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/entry.mock.ts @@ -0,0 +1,28 @@ +/* + * 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 { Entry } from '../exception_item_card/conditions/types'; + +export const includedListTypeEntry: Entry = { + field: '', + operator: 'included', + type: 'list', + list: { id: 'list_id', type: 'boolean' }, +}; + +export const includedMatchTypeEntry: Entry = { + field: '', + operator: 'included', + type: 'match', + value: 'matches value', +}; + +export const includedExistsTypeEntry: Entry = { + field: '', + operator: 'included', + type: 'exists', +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/exception_list_item_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/exception_list_item_schema.mock.ts new file mode 100644 index 0000000000000..a34ddc4dd484f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/exception_list_item_schema.mock.ts @@ -0,0 +1,42 @@ +/* + * 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 type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +export const getExceptionListItemSchemaMock = ( + overrides?: Partial +): ExceptionListItemSchema => ({ + _version: undefined, + comments: [], + created_at: '2020-04-20T15:25:31.830Z', + created_by: 'some user', + description: 'some description', + entries: [ + { + entries: [ + { field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }, + ], + field: 'some.parentField', + type: 'nested', + }, + { field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' }, + ], + expire_time: undefined, + id: '1', + item_id: 'endpoint_list_item', + list_id: 'endpoint_list_id', + meta: {}, + name: 'some name', + namespace_type: 'single', + os_types: [], + tags: ['user added string for a tag', 'malware'], + tie_breaker_id: '6a76b69d-80df-4ab2-8c3e-85f466b06a0e', + type: 'simple', + updated_at: '2020-04-20T15:25:31.830Z', + updated_by: 'some user', + ...(overrides || {}), +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/header.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/header.mock.ts new file mode 100644 index 0000000000000..5ee301495e6f5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/header.mock.ts @@ -0,0 +1,38 @@ +/* + * 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. + */ + +export const handleEdit = jest.fn(); +export const handleDelete = jest.fn(); +export const actions = [ + { + key: 'edit', + icon: 'pencil', + label: 'Edit detection exception', + onClick: handleEdit, + }, + { + key: 'delete', + icon: 'trash', + label: 'Delete detection exception', + onClick: handleDelete, + }, +]; +export const actionsWithDisabledDelete = [ + { + key: 'edit', + icon: 'pencil', + label: 'Edit detection exception', + onClick: handleEdit, + }, + { + key: 'delete', + icon: 'trash', + disabled: true, + label: 'Delete detection exception', + onClick: handleDelete, + }, +]; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/rule_references.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/rule_references.mock.ts new file mode 100644 index 0000000000000..c4eaff274a741 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/rule_references.mock.ts @@ -0,0 +1,41 @@ +/* + * 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 { Rule, RuleReference } from '../types'; + +export const rules: Rule[] = [ + { + exceptions_list: [ + { + id: '123', + list_id: 'i_exist', + namespace_type: 'single', + type: 'detection', + }, + { + id: '456', + list_id: 'i_exist_2', + namespace_type: 'single', + type: 'detection', + }, + ], + id: '1a2b3c', + name: 'Simple Rule Query', + rule_id: 'rule-2', + }, +]; + +export const ruleReference: RuleReference = { + name: 'endpoint list', + id: 'endpoint_list', + referenced_rules: rules, + listId: 'endpoint_list_id', +}; + +export const ruleReferences = { + endpoint_list_id: ruleReference, +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/security_link_component.mock.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/security_link_component.mock.tsx new file mode 100644 index 0000000000000..03c44d7e91667 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/security_link_component.mock.tsx @@ -0,0 +1,36 @@ +/* + * 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 React, { ReactElement } from 'react'; +import { generateLinkedRulesMenuItems } from '../generate_linked_rules_menu_item'; +import { rules } from './rule_references.mock'; +export const securityLinkAnchorComponentMock = ({ + referenceName, + referenceId, +}: { + referenceName: string; + referenceId: string; +}) => ( +
+); + +export const getSecurityLinkAction = (dataTestSubj: string) => + generateLinkedRulesMenuItems({ + dataTestSubj, + linkedRules: [ + ...rules, + { + exceptions_list: [], + id: '2a2b3c', + name: 'Simple Rule Query 2', + rule_id: 'rule-2', + }, + ], + securityLinkAnchorComponent: securityLinkAnchorComponentMock, + }) as ReactElement[]; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/value_list_modal.mock.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/value_list_modal.mock.tsx new file mode 100644 index 0000000000000..e0f9f5d700bed --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/mocks/value_list_modal.mock.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +export const mockShowValueListModal = jest.fn(); +export const MockedShowValueListModal = (props: { children: React.ReactNode }) => { + mockShowValueListModal(props); + return <>{props.children}; +}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.test.tsx similarity index 84% rename from packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.test.tsx index 5eaab267abb52..1467653d432b2 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { fireEvent, render } from '@testing-library/react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.tsx new file mode 100644 index 0000000000000..e7275c4be2c2e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/pagination.tsx @@ -0,0 +1,49 @@ +/* + * 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 React from 'react'; +import type { FC } from 'react'; +import { EuiTablePagination } from '@elastic/eui'; + +import type { PaginationProps } from '../types'; +import { usePagination } from './use_pagination'; + +const PaginationComponent: FC = ({ + dataTestSubj, + ariaLabel, + pagination, + onPaginationChange, +}) => { + const { + pageIndex, + pageCount, + pageSize, + pageSizeOptions, + + handleItemsPerPageChange, + handlePageIndexChange, + } = usePagination({ pagination, onPaginationChange }); + + return ( + + ); +}; + +PaginationComponent.displayName = 'PaginationComponent'; + +export const Pagination = React.memo(PaginationComponent); + +Pagination.displayName = 'Pagination'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.test.ts similarity index 87% rename from packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.test.ts index e90408f1e161b..2126ace9191b5 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { renderHook, act } from '@testing-library/react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.ts similarity index 76% rename from packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.ts index da96624f8b43a..289d5ebcaa268 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/pagination/use_pagination.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { useCallback, useMemo } from 'react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/partial_code_signature_callout/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/partial_code_signature_callout/index.tsx new file mode 100644 index 0000000000000..4339d95b6c4cb --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/partial_code_signature_callout/index.tsx @@ -0,0 +1,32 @@ +/* + * 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 React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; + +import { EuiCallOut } from '@elastic/eui'; + +export const PartialCodeSignatureCallout = () => { + return ( + + + + ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx new file mode 100644 index 0000000000000..dd36c16b9bd8d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/search_bar/index.tsx @@ -0,0 +1,122 @@ +/* + * 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 React, { useCallback } from 'react'; +import type { FC } from 'react'; + +import type { EuiSearchBarProps, IconType, SearchFilterConfig } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiSearchBar } from '@elastic/eui'; +import type { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import type { GetExceptionItemProps } from '../types'; + +const ITEMS_SCHEMA = { + strict: true, + fields: { + created_by: { + type: 'string', + }, + description: { + type: 'string', + }, + id: { + type: 'string', + }, + item_id: { + type: 'string', + }, + list_id: { + type: 'string', + }, + name: { + type: 'string', + }, + os_types: { + type: 'string', + }, + tags: { + type: 'string', + }, + }, +}; +interface SearchBarProps { + addExceptionButtonText?: string; + placeholdertext?: string; + canAddException?: boolean; // TODO what is the default value + + // TODO: REFACTOR: not to send the listType and handle it in the Parent + // Exception list type used to determine what type of item is + // being created when "onAddExceptionClick" is invoked + listType: ExceptionListTypeEnum; + isSearching?: boolean; + dataTestSubj?: string; + filters?: SearchFilterConfig[]; // TODO about filters + isButtonFilled?: boolean; + buttonIconType?: IconType; + onSearch: (arg: GetExceptionItemProps) => void; + onAddExceptionClick: (type: ExceptionListTypeEnum) => void; +} +const SearchBarComponent: FC = ({ + addExceptionButtonText, + placeholdertext, + canAddException, + listType, + isSearching, + dataTestSubj, + filters = [], + isButtonFilled = true, + buttonIconType, + onSearch, + onAddExceptionClick, +}) => { + const handleOnSearch = useCallback>( + ({ queryText }): void => { + onSearch({ search: queryText }); + }, + [onSearch] + ); + + const handleAddException = useCallback(() => { + // TODO: ASK YARA why we need to send the listType + onAddExceptionClick(listType); + }, [onAddExceptionClick, listType]); + + return ( + + + + + {!canAddException && ( + + + {addExceptionButtonText} + + + )} + + ); +}; + +SearchBarComponent.displayName = 'SearchBarComponent'; + +export const SearchBar = React.memo(SearchBarComponent); + +SearchBar.displayName = 'SearchBar'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx similarity index 88% rename from packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx index b1eadded0e3f8..a7eaa7ba47ad0 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/search_bar/search_bar.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/__snapshots__/text_with_edit.test.tsx.snap b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/__snapshots__/text_with_edit.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-exception-list-components/src/text_with_edit/__snapshots__/text_with_edit.test.tsx.snap rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/__snapshots__/text_with_edit.test.tsx.snap diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/index.tsx new file mode 100644 index 0000000000000..1428dcfa238ea --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/index.tsx @@ -0,0 +1,51 @@ +/* + * 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 React, { FC } from 'react'; +import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { Interpolation, Theme } from '@emotion/react'; +import { textWithEditContainerCss, editIconCss } from './text_with_edit.styles'; +interface TextWithEditProps { + isReadonly: boolean; + dataTestSubj?: string; + text: string; + textCss?: Interpolation; + onEdit?: () => void; +} + +const TextWithEditComponent: FC = ({ + isReadonly, + dataTestSubj, + text, + onEdit, + textCss, +}) => { + return ( + + + + {text} + + + + {isReadonly ? null : ( + (typeof onEdit === 'function' ? onEdit() : null)} + /> + )} + + + ); +}; +TextWithEditComponent.displayName = 'TextWithEditComponent'; + +export const TextWithEdit = React.memo(TextWithEditComponent); + +TextWithEdit.displayName = 'TextWithEdit'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.styles.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.styles.ts new file mode 100644 index 0000000000000..d61aaab0f9be6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.styles.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; + +export const textWithEditContainerCss = css` + display: flex; + width: fit-content; + align-items: baseline; + padding-bottom: ${euiThemeVars.euiSizeS}; + h1 { + margin-bottom: 0; + } +`; +export const editIconCss = css` + button { + margin-left: -${euiThemeVars.euiSizeM}; + } +`; diff --git a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.test.tsx similarity index 84% rename from packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.test.tsx index eab0eb7817d8c..24b5eec6e3350 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/text_with_edit/text_with_edit.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { fireEvent, render } from '@testing-library/react'; @@ -35,6 +33,7 @@ describe('TextWithEdit', () => { isReadonly={false} dataTestSubj="TextWithEditTest" text="Test" + // eslint-disable-next-line @typescript-eslint/no-explicit-any onEdit={onEdit as any} /> ); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/translations.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/translations.ts new file mode 100644 index 0000000000000..5660ac3564c7d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/translations.ts @@ -0,0 +1,154 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const EMPTY_VIEWER_STATE_EMPTY_TITLE = i18n.translate( + 'exceptionList-components.empty.viewer.state.empty.title', + { + defaultMessage: 'Add exceptions to this list', + } +); + +export const EMPTY_VIEWER_STATE_EMPTY_BODY = i18n.translate( + 'exceptionList-components.empty.viewer.state.empty.body', + { + defaultMessage: 'There is no exception in your list. Create your first exception.', + } +); +export const EMPTY_VIEWER_STATE_EMPTY_SEARCH_TITLE = i18n.translate( + 'exceptionList-components.empty.viewer.state.empty_search.search.title', + { + defaultMessage: 'No results match your search criteria', + } +); + +export const EMPTY_VIEWER_STATE_EMPTY_SEARCH_BODY = i18n.translate( + 'exceptionList-components.empty.viewer.state.empty_search.body', + { + defaultMessage: 'Try modifying your search', + } +); + +export const EMPTY_VIEWER_STATE_EMPTY_VIEWER_BUTTON = (exceptionType: string) => + i18n.translate('exceptionList-components.empty.viewer.state.empty.viewer_button', { + values: { exceptionType }, + defaultMessage: 'Create {exceptionType} exception', + }); + +export const EMPTY_VIEWER_STATE_ERROR_TITLE = i18n.translate( + 'exceptionList-components.empty.viewer.state.error_title', + { + defaultMessage: 'Unable to load exception items', + } +); + +export const EMPTY_VIEWER_STATE_ERROR_BODY = i18n.translate( + 'exceptionList-components.empty.viewer.state.error_body', + { + defaultMessage: + 'There was an error loading the exception items. Contact your administrator for help.', + } +); +export const EXCEPTION_LIST_HEADER_EXPORT_ACTION = i18n.translate( + 'exceptionList-components.exception_list_header_export_action', + { + defaultMessage: 'Export exception list', + } +); +export const EXCEPTION_LIST_HEADER_DELETE_ACTION = i18n.translate( + 'exceptionList-components.exception_list_header_delete_action', + { + defaultMessage: 'Delete exception list', + } +); +export const EXCEPTION_LIST_HEADER_DUPLICATE_ACTION = i18n.translate( + 'exceptionList-components.exception_list_header_duplicate_action', + { + defaultMessage: 'Duplicate exception list', + } +); +export const EXCEPTION_LIST_HEADER_LINK_RULES_BUTTON = i18n.translate( + 'exceptionList-components.exception_list_header_link_rules_button', + { + defaultMessage: 'Link rules', + } +); + +export const EXCEPTION_LIST_HEADER_LINKED_RULES = (noOfRules: number) => + i18n.translate('exceptionList-components.exception_list_header_linked_rules', { + values: { noOfRules }, + defaultMessage: 'Linked to {noOfRules} rules', + }); + +export const EXCEPTION_LIST_HEADER_BREADCRUMB = i18n.translate( + 'exceptionList-components.exception_list_header_breadcrumb', + { + defaultMessage: 'Shared Exception Lists', + } +); + +export const EXCEPTION_LIST_HEADER_LIST_ID = i18n.translate( + 'exceptionList-components.exception_list_header_list_id', + { + defaultMessage: 'List ID', + } +); + +export const EXCEPTION_LIST_HEADER_NAME = i18n.translate( + 'exceptionList-components.exception_list_header_name', + { + defaultMessage: 'Add a name', + } +); + +export const EXCEPTION_LIST_HEADER_DESCRIPTION = i18n.translate( + 'exceptionList-components.exception_list_header_description', + { + defaultMessage: 'Add a description', + } +); + +export const EXCEPTION_LIST_HEADER_EDIT_MODAL_TITLE = (listName: string) => + i18n.translate('exceptionList-components.exception_list_header_edit_modal_name', { + defaultMessage: 'Edit {listName}', + values: { listName }, + }); + +export const EXCEPTION_LIST_HEADER_EDIT_MODAL_SAVE_BUTTON = i18n.translate( + 'exceptionList-components.exception_list_header_edit_modal_save_button', + { + defaultMessage: 'Save', + } +); + +export const EXCEPTION_LIST_HEADER_EDIT_MODAL_CANCEL_BUTTON = i18n.translate( + 'exceptionList-components.exception_list_header_edit_modal_cancel_button', + { + defaultMessage: 'Cancel', + } +); +export const EXCEPTION_LIST_HEADER_NAME_TEXTBOX = i18n.translate( + 'exceptionList-components.exception_list_header_Name_textbox', + { + defaultMessage: 'Name', + } +); + +export const EXCEPTION_LIST_HEADER_DESCRIPTION_TEXTBOX = i18n.translate( + 'exceptionList-components.exception_list_header_description_textbox', + { + defaultMessage: 'Description (optional)', + } +); + +export const LIST_NAME_REQUIRED_ERROR = i18n.translate( + 'exceptionList-components.exception_list_header_description_textboxexceptionList-components.exception_list_header_name_required_eror', + { + defaultMessage: 'List name cannot be empty', + } +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/types/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/types/index.ts new file mode 100644 index 0000000000000..d628cd0137972 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/types/index.ts @@ -0,0 +1,75 @@ +/* + * 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 { ListArray } from '@kbn/securitysolution-io-ts-list-types'; + +import type { Pagination } from '@elastic/eui'; +import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; + +export interface GetExceptionItemProps { + pagination?: PaginationProps['pagination']; + search?: string; + filters?: string; +} + +export interface PaginationProps { + dataTestSubj?: string; + ariaLabel?: string; + pagination: Pagination & { pageSize: number }; + onPaginationChange: (arg: GetExceptionItemProps) => void; +} + +export enum ViewerStatus { + ERROR = 'error', + EMPTY = 'empty', + EMPTY_SEARCH = 'empty_search', + LOADING = 'loading', + SEARCHING = 'searching', + DELETING = 'deleting', +} + +export interface ExceptionListSummaryProps { + pagination: Pagination; + // Corresponds to last time exception items were fetched + lastUpdated: string | number | null; +} + +export type ViewerFlyoutName = 'addException' | 'editException' | null; + +export interface RuleReferences { + [key: string]: RuleReference; +} + +export interface ExceptionListItemIdentifiers { + id: string; + name: string; + namespaceType: NamespaceType; +} + +export enum ListTypeText { + ENDPOINT = 'endpoint', + DETECTION = 'empty', + RULE_DEFAULT = 'empty_search', +} +export interface Rule { + name: string; + id: string; + rule_id: string; + exceptions_list?: ListArray; +} + +export interface RuleReference { + name: string; + id: string; + referenced_rules: Rule[]; + listId?: string; +} + +export interface ListDetails { + name: string; + description?: string; +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/index.ts new file mode 100644 index 0000000000000..968bc9666b090 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { ValueWithSpaceWarning } from './value_with_space_warning'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.test.ts similarity index 84% rename from packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.test.ts index 51954c0140e61..570399a5ecb23 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { renderHook } from '@testing-library/react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.ts new file mode 100644 index 0000000000000..252f05f4d1020 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/use_value_with_space_warning.ts @@ -0,0 +1,31 @@ +/* + * 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 { paramContainsSpace, autoCompletei18n } from '@kbn/securitysolution-autocomplete'; + +interface UseValueWithSpaceWarningResult { + showSpaceWarningIcon: boolean; + warningText: string; +} +interface UseValueWithSpaceWarningProps { + value: string | string[]; + tooltipIconText?: string; +} + +export const useValueWithSpaceWarning = ({ + value, + tooltipIconText, +}: UseValueWithSpaceWarningProps): UseValueWithSpaceWarningResult => { + const showSpaceWarningIcon = Array.isArray(value) + ? value.find(paramContainsSpace) + : paramContainsSpace(value); + + return { + showSpaceWarningIcon: !!showSpaceWarningIcon, + warningText: tooltipIconText || autoCompletei18n.FIELD_SPACE_WARNING, + }; +}; diff --git a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.test.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.test.tsx similarity index 81% rename from packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.test.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.test.tsx index 8f780181e0528..a500f13af6e16 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.test.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.test.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.tsx similarity index 75% rename from packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.tsx rename to x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.tsx index c736982142b1e..c73a39a516ed8 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.tsx +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/value_with_space_warning/value_with_space_warning.tsx @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 React from 'react'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/wildcard_with_wrong_operator_callout/index.tsx b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/wildcard_with_wrong_operator_callout/index.tsx new file mode 100644 index 0000000000000..b21259f4ed895 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/src/wildcard_with_wrong_operator_callout/index.tsx @@ -0,0 +1,51 @@ +/* + * 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 React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; + +import { EuiCallOut } from '@elastic/eui'; + +export const WildCardWithWrongOperatorCallout = () => { + return ( + +

+ + {i18n.translate( + 'exceptionList-components.wildcardWithWrongOperatorCallout.changeTheOperator', + { defaultMessage: 'Change the operator' } + )} + + ), + matches: ( + + {i18n.translate( + 'exceptionList-components.wildcardWithWrongOperatorCallout.matches', + { defaultMessage: 'matches' } + )} + + ), + }} + /> +

+
+ ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/tsconfig.json new file mode 100644 index 0000000000000..5378a8fbdfe1a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components/tsconfig.json @@ -0,0 +1,27 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react", + "@emotion/react/types/css-prop" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + "**/*.d.ts" + ], + "kbn_references": [ + "@kbn/securitysolution-io-ts-list-types", + "@kbn/securitysolution-autocomplete", + "@kbn/ui-theme", + "@kbn/i18n", + "@kbn/i18n-react", + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-exceptions-common/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/README.md similarity index 100% rename from packages/kbn-securitysolution-exceptions-common/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/README.md diff --git a/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.gen.ts similarity index 78% rename from packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.gen.ts index a9acaee37cefa..2c7dc29dd182a 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.schema.yaml similarity index 79% rename from packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.schema.yaml index 5925d0bd923c0..e7a399c2d7a82 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list/create_exception_list.schema.yaml @@ -59,29 +59,29 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 409: description: Exception list already exists response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.gen.ts similarity index 85% rename from packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.gen.ts index 9adf64b6b083f..dba75c11fde83 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.schema.yaml similarity index 78% rename from packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.schema.yaml index 47fa2895d27c6..2913d8c5c07d7 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_exception_list_item/create_exception_list_item.schema.yaml @@ -69,32 +69,32 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 409: description: Exception list item already exists response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: x-codegen-enabled: true @@ -103,7 +103,7 @@ components: type: object properties: comment: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' required: - comment diff --git a/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.gen.ts similarity index 88% rename from packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.gen.ts index 77437ff51618c..e2fa379cdc528 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.schema.yaml similarity index 78% rename from packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.schema.yaml index 6162d00d78ae8..b7b2db3fabefd 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_rule_exceptions/create_rule_exceptions.schema.yaml @@ -9,7 +9,7 @@ paths: operationId: CreateRuleExceptionListItems x-codegen-enabled: true summary: Create rule exception list items - description: Create exception items that apply to a single detection rule. + description: Create exception items that apply to a single detection rule. parameters: - name: id in: path @@ -45,37 +45,37 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: schemas: RuleId: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/UUID' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/UUID' CreateRuleExceptionListItemComment: type: object properties: comment: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' required: - comment diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.gen.ts new file mode 100644 index 0000000000000..07650ee2d0c01 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.gen.ts @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Create shared exception list API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { + ExceptionListName, + ExceptionListDescription, + ExceptionList, +} from '../model/exception_list_common.gen'; + +export type CreateSharedExceptionListRequestBody = z.infer< + typeof CreateSharedExceptionListRequestBody +>; +export const CreateSharedExceptionListRequestBody = z.object({ + name: ExceptionListName, + description: ExceptionListDescription, +}); +export type CreateSharedExceptionListRequestBodyInput = z.input< + typeof CreateSharedExceptionListRequestBody +>; + +export type CreateSharedExceptionListResponse = z.infer; +export const CreateSharedExceptionListResponse = ExceptionList; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.schema.yaml new file mode 100644 index 0000000000000..040acca3ebd77 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/create_shared_exceptions_list/create_shared_exceptions_list.schema.yaml @@ -0,0 +1,68 @@ +openapi: 3.0.0 +info: + title: Create shared exception list API endpoint + version: '2023-10-31' +paths: + /api/exceptions/shared: + post: + x-labels: [serverless, ess] + operationId: CreateSharedExceptionList + x-codegen-enabled: true + summary: Create a shared exception list + description: | + An exception list groups exception items and can be associated with detection rules. A shared exception list can apply to multiple detection rules. + > info + > All exception items added to the same list are evaluated using `OR` logic. That is, if any of the items in a list evaluate to `true`, the exception prevents the rule from generating an alert. Likewise, `OR` logic is used for evaluating exceptions when more than one exception list is assigned to a rule. To use the `AND` operator, you can define multiple clauses (`entries`) in a single exception item. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListName' + description: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListDescription' + required: + - name + - description + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionList' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 409: + description: Exception list already exists response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.gen.ts similarity index 75% rename from packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.gen.ts index a12512aab1374..0842dc7c74637 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.schema.yaml new file mode 100644 index 0000000000000..2912070635b8f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list/delete_exception_list.schema.yaml @@ -0,0 +1,70 @@ +openapi: 3.0.0 +info: + title: Delete exception list API endpoint + version: '2023-10-31' +paths: + /api/exception_lists: + delete: + x-labels: [serverless, ess] + operationId: DeleteExceptionList + x-codegen-enabled: true + summary: Delete an exception list + description: Delete an exception list using the `id` or `list_id` field. + parameters: + - name: id + in: query + required: false + description: Either `id` or `list_id` must be specified + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListId' + - name: list_id + in: query + required: false + description: Either `id` or `list_id` must be specified + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' + - name: namespace_type + in: query + required: false + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' + default: single + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionList' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: Exception list not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.gen.ts similarity index 76% rename from packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.gen.ts index a93af0cf3d4c2..429568c33f1c6 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.schema.yaml new file mode 100644 index 0000000000000..05f997307a4ca --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/delete_exception_list_item/delete_exception_list_item.schema.yaml @@ -0,0 +1,70 @@ +openapi: 3.0.0 +info: + title: Delete exception list item API endpoint + version: '2023-10-31' +paths: + /api/exception_lists/items: + delete: + x-labels: [serverless, ess] + operationId: DeleteExceptionListItem + x-codegen-enabled: true + summary: Delete an exception list item + description: Delete an exception list item using the `id` or `item_id` field. + parameters: + - name: id + in: query + required: false + description: Either `id` or `item_id` must be specified + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemId' + - name: item_id + in: query + required: false + description: Either `id` or `item_id` must be specified + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemHumanId' + - name: namespace_type + in: query + required: false + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' + default: single + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: Exception list item not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.gen.ts similarity index 75% rename from packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.gen.ts index 61de17abe06f8..d259d37b23487 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.schema.yaml new file mode 100644 index 0000000000000..80620c4adf7f7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/duplicate_exception_list/duplicate_exception_list.schema.yaml @@ -0,0 +1,71 @@ +openapi: 3.0.0 +info: + title: Duplicate exception list API endpoint + version: '2023-10-31' +paths: + /api/exception_lists/_duplicate: + post: + x-labels: [serverless, ess] + operationId: DuplicateExceptionList + x-codegen-enabled: true + summary: Duplicate an exception list + description: Duplicate an existing exception list. + parameters: + - name: list_id + in: query + required: true + description: Exception list's human identifier + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' + - name: namespace_type + in: query + required: true + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' + - name: include_expired_exceptions + in: query + required: true + description: Determines whether to include expired exceptions in the exported list + schema: + type: string + enum: ['true', 'false'] + default: 'true' + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionList' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 405: + description: Exception list to duplicate not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.gen.ts new file mode 100644 index 0000000000000..280884c7d749d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.gen.ts @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Export exception list API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { + ExceptionListId, + ExceptionListHumanId, + ExceptionNamespaceType, +} from '../model/exception_list_common.gen'; + +export type ExportExceptionListRequestQuery = z.infer; +export const ExportExceptionListRequestQuery = z.object({ + /** + * Exception list's identifier + */ + id: ExceptionListId, + /** + * Exception list's human identifier + */ + list_id: ExceptionListHumanId, + namespace_type: ExceptionNamespaceType, + /** + * Determines whether to include expired exceptions in the exported list + */ + include_expired_exceptions: z.enum(['true', 'false']).default('true'), +}); +export type ExportExceptionListRequestQueryInput = z.input; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.schema.yaml new file mode 100644 index 0000000000000..89f97ff8bbe6a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/export_exception_list/export_exception_list.schema.yaml @@ -0,0 +1,79 @@ +openapi: 3.0.0 +info: + title: Export exception list API endpoint + version: '2023-10-31' +paths: + /api/exception_lists/_export: + post: + x-labels: [serverless, ess] + operationId: ExportExceptionList + x-codegen-enabled: true + summary: Export an exception list + description: Export an exception list and its associated items to an NDJSON file. + parameters: + - name: id + in: query + required: true + description: Exception list's identifier + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListId' + - name: list_id + in: query + required: true + description: Exception list's human identifier + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' + - name: namespace_type + in: query + required: true + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' + - name: include_expired_exceptions + in: query + required: true + description: Determines whether to include expired exceptions in the exported list + schema: + type: string + enum: ['true', 'false'] + default: 'true' + responses: + 200: + description: Successful response + content: + application/ndjson: + schema: + type: string + format: binary + description: A `.ndjson` file containing specified exception list and its items + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: Exception list not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.gen.ts similarity index 86% rename from packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.gen.ts index 99ed1b3a31ddc..d7606bbccff37 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.schema.yaml similarity index 77% rename from packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.schema.yaml index e40f780af03ef..6d390e9ecdf69 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_list_items/find_exception_list_items.schema.yaml @@ -65,7 +65,7 @@ paths: required: false description: Determines which field is used to sort the results schema: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - name: sort_order in: query required: false @@ -107,34 +107,34 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 404: description: Exception list not found response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: schemas: FindExceptionListItemsFilter: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' diff --git a/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.gen.ts similarity index 85% rename from packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.gen.ts index 83a68b4232e8b..82f5de2f5a157 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.schema.yaml similarity index 82% rename from packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.schema.yaml index c46dacbab01d0..49017d6d45912 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/find_exception_lists/find_exception_lists.schema.yaml @@ -93,26 +93,26 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: schemas: diff --git a/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.gen.ts similarity index 86% rename from packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.gen.ts index ea24803e79456..738ce79dd97d0 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.schema.yaml similarity index 85% rename from packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.schema.yaml index 8ae3ac1aa2c0c..95bc9ee508e5a 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/import_exceptions/import_exceptions.schema.yaml @@ -92,26 +92,26 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: schemas: diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/index.ts new file mode 100644 index 0000000000000..014fe58cfce09 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './model/exception_list_common.gen'; +export * from './model/exception_list_item_entry.gen'; +export * from './create_exception_list_item/create_exception_list_item.gen'; +export * from './create_rule_exceptions/create_rule_exceptions.gen'; +export * from './create_shared_exceptions_list/create_shared_exceptions_list.gen'; +export * from './create_exception_list/create_exception_list.gen'; +export * from './delete_exception_list_item/delete_exception_list_item.gen'; +export * from './delete_exception_list/delete_exception_list.gen'; +export * from './duplicate_exception_list/duplicate_exception_list.gen'; +export * from './export_exception_list/export_exception_list.gen'; +export * from './find_exception_list_items/find_exception_list_items.gen'; +export * from './find_exception_lists/find_exception_lists.gen'; +export * from './import_exceptions/import_exceptions.gen'; +export * from './read_exception_list_item/read_exception_list_item.gen'; +export * from './read_exception_list/read_exception_list.gen'; +export * from './read_exception_list_summary/read_exception_list_summary.gen'; +export * from './update_exception_list_item/update_exception_list_item.gen'; +export * from './update_exception_list/update_exception_list.gen'; diff --git a/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.gen.ts similarity index 94% rename from packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.gen.ts index 1f2d9e7387da3..2ee44afa69b9f 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml similarity index 83% rename from packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml index ebcecc9c916f7..4ca9326ec6c92 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_common.schema.yaml @@ -7,10 +7,10 @@ components: x-codegen-enabled: true schemas: ExceptionListId: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' ExceptionListHumanId: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' description: Human readable string identifier, e.g. `trusted-linux-processes` ExceptionListType: @@ -122,17 +122,17 @@ components: - updated_by ExceptionListItemId: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' ExceptionListItemHumanId: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' ExceptionListItemType: type: string enum: [simple] ExceptionListItemName: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' ExceptionListItemDescription: type: string @@ -144,7 +144,7 @@ components: ExceptionListItemTags: type: array items: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' ExceptionListItemOsType: type: string @@ -162,19 +162,19 @@ components: type: object properties: id: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' comment: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' created_at: type: string format: date-time created_by: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' updated_at: type: string format: date-time updated_by: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' required: - id - comment @@ -278,7 +278,7 @@ components: comments: $ref: '#/components/schemas/ExceptionListItemCommentArray' version: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' tie_breaker_id: type: string created_at: diff --git a/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.gen.ts similarity index 90% rename from packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.gen.ts index 0b7f0233ba429..272e5e7d6c356 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.schema.yaml new file mode 100644 index 0000000000000..ab8c427344a0d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/model/exception_list_item_entry.schema.yaml @@ -0,0 +1,147 @@ +openapi: 3.0.0 +info: + title: Common Exception List Item Entry Attributes + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + ExceptionListItemEntryOperator: + type: string + enum: [excluded, included] + + ExceptionListItemEntryMatch: + type: object + properties: + type: + type: string + enum: [match] + field: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + value: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + required: + - type + - field + - value + - operator + + ExceptionListItemEntryMatchAny: + type: object + properties: + type: + type: string + enum: [match_any] + field: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + value: + type: array + items: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + minItems: 1 + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + required: + - type + - field + - value + - operator + + ExceptionListItemEntryList: + type: object + properties: + type: + type: string + enum: [list] + field: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + list: + type: object + properties: + id: + $ref: '../../../kbn-securitysolution-lists-common/api/model/list_common.schema.yaml#/components/schemas/ListId' + type: + $ref: '../../../kbn-securitysolution-lists-common/api/model/list_common.schema.yaml#/components/schemas/ListType' + required: [id, type] + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + required: + - type + - field + - list + - operator + + ExceptionListItemEntryExists: + type: object + properties: + type: + type: string + enum: [exists] + field: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + required: + - type + - field + - operator + + ExceptionListItemEntryNestedEntryItem: + oneOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + + ExceptionListItemEntryNested: + type: object + properties: + type: + type: string + enum: [nested] + field: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + entries: + type: array + items: + $ref: '#/components/schemas/ExceptionListItemEntryNestedEntryItem' + minItems: 1 + required: + - type + - field + - entries + + ExceptionListItemEntryMatchWildcard: + type: object + properties: + type: + type: string + enum: [wildcard] + field: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + value: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + required: + - type + - field + - value + - operator + + ExceptionListItemEntry: + discriminator: + propertyName: type + anyOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryList' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + - $ref: '#/components/schemas/ExceptionListItemEntryNested' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchWildcard' + + ExceptionListItemEntryArray: + type: array + items: + $ref: '#/components/schemas/ExceptionListItemEntry' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts new file mode 100644 index 0000000000000..bfa84f18fa7c2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts @@ -0,0 +1,425 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Exceptions API client for quickstart + * version: Bundle (no version) + */ + +import type { KbnClient } from '@kbn/test'; +import { ToolingLog } from '@kbn/tooling-log'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { replaceParams } from '@kbn/openapi-common/shared'; +import { catchAxiosErrorFormatAndThrow } from '@kbn/securitysolution-utils'; + +import type { + CreateExceptionListItemRequestBodyInput, + CreateExceptionListItemResponse, +} from './create_exception_list_item/create_exception_list_item.gen'; +import type { + CreateExceptionListRequestBodyInput, + CreateExceptionListResponse, +} from './create_exception_list/create_exception_list.gen'; +import type { + CreateRuleExceptionListItemsRequestParamsInput, + CreateRuleExceptionListItemsRequestBodyInput, + CreateRuleExceptionListItemsResponse, +} from './create_rule_exceptions/create_rule_exceptions.gen'; +import type { + CreateSharedExceptionListRequestBodyInput, + CreateSharedExceptionListResponse, +} from './create_shared_exceptions_list/create_shared_exceptions_list.gen'; +import type { + DeleteExceptionListItemRequestQueryInput, + DeleteExceptionListItemResponse, +} from './delete_exception_list_item/delete_exception_list_item.gen'; +import type { + DeleteExceptionListRequestQueryInput, + DeleteExceptionListResponse, +} from './delete_exception_list/delete_exception_list.gen'; +import type { + DuplicateExceptionListRequestQueryInput, + DuplicateExceptionListResponse, +} from './duplicate_exception_list/duplicate_exception_list.gen'; +import type { ExportExceptionListRequestQueryInput } from './export_exception_list/export_exception_list.gen'; +import type { + FindExceptionListItemsRequestQueryInput, + FindExceptionListItemsResponse, +} from './find_exception_list_items/find_exception_list_items.gen'; +import type { + FindExceptionListsRequestQueryInput, + FindExceptionListsResponse, +} from './find_exception_lists/find_exception_lists.gen'; +import type { + ImportExceptionListRequestQueryInput, + ImportExceptionListResponse, +} from './import_exceptions/import_exceptions.gen'; +import type { + ReadExceptionListItemRequestQueryInput, + ReadExceptionListItemResponse, +} from './read_exception_list_item/read_exception_list_item.gen'; +import type { + ReadExceptionListSummaryRequestQueryInput, + ReadExceptionListSummaryResponse, +} from './read_exception_list_summary/read_exception_list_summary.gen'; +import type { + ReadExceptionListRequestQueryInput, + ReadExceptionListResponse, +} from './read_exception_list/read_exception_list.gen'; +import type { + UpdateExceptionListItemRequestBodyInput, + UpdateExceptionListItemResponse, +} from './update_exception_list_item/update_exception_list_item.gen'; +import type { + UpdateExceptionListRequestBodyInput, + UpdateExceptionListResponse, +} from './update_exception_list/update_exception_list.gen'; + +export interface ClientOptions { + kbnClient: KbnClient; + log: ToolingLog; +} + +export class Client { + readonly kbnClient: KbnClient; + readonly log: ToolingLog; + + constructor(options: ClientOptions) { + this.kbnClient = options.kbnClient; + this.log = options.log; + } + /** + * An exception list groups exception items and can be associated with detection rules. You can assign detection rules with multiple exception lists. +> info +> All exception items added to the same list are evaluated using `OR` logic. That is, if any of the items in a list evaluate to `true`, the exception prevents the rule from generating an alert. Likewise, `OR` logic is used for evaluating exceptions when more than one exception list is assigned to a rule. To use the `AND` operator, you can define multiple clauses (`entries`) in a single exception item. + + */ + async createExceptionList(props: CreateExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Create an exception item and associate it with the specified exception list. +> info +> Before creating exception items, you must create an exception list. + + */ + async createExceptionListItem(props: CreateExceptionListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateExceptionListItem`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Create exception items that apply to a single detection rule. + */ + async createRuleExceptionListItems(props: CreateRuleExceptionListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateRuleExceptionListItems`); + return this.kbnClient + .request({ + path: replaceParams('/api/detection_engine/rules/{id}/exceptions', props.params), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * An exception list groups exception items and can be associated with detection rules. A shared exception list can apply to multiple detection rules. +> info +> All exception items added to the same list are evaluated using `OR` logic. That is, if any of the items in a list evaluate to `true`, the exception prevents the rule from generating an alert. Likewise, `OR` logic is used for evaluating exceptions when more than one exception list is assigned to a rule. To use the `AND` operator, you can define multiple clauses (`entries`) in a single exception item. + + */ + async createSharedExceptionList(props: CreateSharedExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateSharedExceptionList`); + return this.kbnClient + .request({ + path: '/api/exceptions/shared', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Delete an exception list using the `id` or `list_id` field. + */ + async deleteExceptionList(props: DeleteExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Delete an exception list item using the `id` or `item_id` field. + */ + async deleteExceptionListItem(props: DeleteExceptionListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteExceptionListItem`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Duplicate an existing exception list. + */ + async duplicateExceptionList(props: DuplicateExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API DuplicateExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists/_duplicate', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Export an exception list and its associated items to an NDJSON file. + */ + async exportExceptionList(props: ExportExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API ExportExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists/_export', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get a list of all exception list items in the specified list. + */ + async findExceptionListItems(props: FindExceptionListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API FindExceptionListItems`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get a list of all exception lists. + */ + async findExceptionLists(props: FindExceptionListsProps) { + this.log.info(`${new Date().toISOString()} Calling API FindExceptionLists`); + return this.kbnClient + .request({ + path: '/api/exception_lists/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Import an exception list and its associated items from an NDJSON file. + */ + async importExceptionList(props: ImportExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API ImportExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists/_import', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.attachment, + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get the details of an exception list using the `id` or `list_id` field. + */ + async readExceptionList(props: ReadExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get the details of an exception list item using the `id` or `item_id` field. + */ + async readExceptionListItem(props: ReadExceptionListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadExceptionListItem`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get a summary of the specified exception list. + */ + async readExceptionListSummary(props: ReadExceptionListSummaryProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadExceptionListSummary`); + return this.kbnClient + .request({ + path: '/api/exception_lists/summary', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update an exception list using the `id` or `list_id` field. + */ + async updateExceptionList(props: UpdateExceptionListProps) { + this.log.info(`${new Date().toISOString()} Calling API UpdateExceptionList`); + return this.kbnClient + .request({ + path: '/api/exception_lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update an exception list item using the `id` or `item_id` field. + */ + async updateExceptionListItem(props: UpdateExceptionListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API UpdateExceptionListItem`); + return this.kbnClient + .request({ + path: '/api/exception_lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } +} + +export interface CreateExceptionListProps { + body: CreateExceptionListRequestBodyInput; +} +export interface CreateExceptionListItemProps { + body: CreateExceptionListItemRequestBodyInput; +} +export interface CreateRuleExceptionListItemsProps { + params: CreateRuleExceptionListItemsRequestParamsInput; + body: CreateRuleExceptionListItemsRequestBodyInput; +} +export interface CreateSharedExceptionListProps { + body: CreateSharedExceptionListRequestBodyInput; +} +export interface DeleteExceptionListProps { + query: DeleteExceptionListRequestQueryInput; +} +export interface DeleteExceptionListItemProps { + query: DeleteExceptionListItemRequestQueryInput; +} +export interface DuplicateExceptionListProps { + query: DuplicateExceptionListRequestQueryInput; +} +export interface ExportExceptionListProps { + query: ExportExceptionListRequestQueryInput; +} +export interface FindExceptionListItemsProps { + query: FindExceptionListItemsRequestQueryInput; +} +export interface FindExceptionListsProps { + query: FindExceptionListsRequestQueryInput; +} +export interface ImportExceptionListProps { + query: ImportExceptionListRequestQueryInput; + attachment: FormData; +} +export interface ReadExceptionListProps { + query: ReadExceptionListRequestQueryInput; +} +export interface ReadExceptionListItemProps { + query: ReadExceptionListItemRequestQueryInput; +} +export interface ReadExceptionListSummaryProps { + query: ReadExceptionListSummaryRequestQueryInput; +} +export interface UpdateExceptionListProps { + body: UpdateExceptionListRequestBodyInput; +} +export interface UpdateExceptionListItemProps { + body: UpdateExceptionListItemRequestBodyInput; +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.gen.ts new file mode 100644 index 0000000000000..87db0f9e75623 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.gen.ts @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Read exception list API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { + ExceptionListId, + ExceptionListHumanId, + ExceptionNamespaceType, + ExceptionList, +} from '../model/exception_list_common.gen'; + +export type ReadExceptionListRequestQuery = z.infer; +export const ReadExceptionListRequestQuery = z.object({ + /** + * Either `id` or `list_id` must be specified + */ + id: ExceptionListId.optional(), + /** + * Either `id` or `list_id` must be specified + */ + list_id: ExceptionListHumanId.optional(), + namespace_type: ExceptionNamespaceType.optional().default('single'), +}); +export type ReadExceptionListRequestQueryInput = z.input; + +export type ReadExceptionListResponse = z.infer; +export const ReadExceptionListResponse = ExceptionList; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.schema.yaml new file mode 100644 index 0000000000000..e50147083dafe --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list/read_exception_list.schema.yaml @@ -0,0 +1,70 @@ +openapi: 3.0.0 +info: + title: Read exception list API endpoint + version: '2023-10-31' +paths: + /api/exception_lists: + get: + x-labels: [serverless, ess] + operationId: ReadExceptionList + x-codegen-enabled: true + summary: Get exception list details + description: Get the details of an exception list using the `id` or `list_id` field. + parameters: + - name: id + in: query + required: false + description: Either `id` or `list_id` must be specified + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListId' + - name: list_id + in: query + required: false + description: Either `id` or `list_id` must be specified + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' + - name: namespace_type + in: query + required: false + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' + default: single + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionList' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: Exception list item not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.gen.ts similarity index 75% rename from packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.gen.ts index 4de512301cd83..02f6d10558389 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.schema.yaml new file mode 100644 index 0000000000000..6d7fac7767182 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_item/read_exception_list_item.schema.yaml @@ -0,0 +1,70 @@ +openapi: 3.0.0 +info: + title: Read exception list item API endpoint + version: '2023-10-31' +paths: + /api/exception_lists/items: + get: + x-labels: [serverless, ess] + operationId: ReadExceptionListItem + x-codegen-enabled: true + summary: Get an exception list item + description: Get the details of an exception list item using the `id` or `item_id` field. + parameters: + - name: id + in: query + required: false + description: Either `id` or `item_id` must be specified + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemId' + - name: item_id + in: query + required: false + description: Either `id` or `item_id` must be specified + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItemHumanId' + - name: namespace_type + in: query + required: false + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' + default: single + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: Exception list item not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.gen.ts similarity index 79% rename from packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.gen.ts index 3e3230dddb0aa..8807f4b7e7812 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.schema.yaml new file mode 100644 index 0000000000000..02fc3c9c8f6fe --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/read_exception_list_summary/read_exception_list_summary.schema.yaml @@ -0,0 +1,89 @@ +openapi: 3.0.0 +info: + title: Read exception list summary API endpoint + version: '2023-10-31' +paths: + /api/exception_lists/summary: + get: + x-labels: [serverless, ess] + operationId: ReadExceptionListSummary + x-codegen-enabled: true + summary: Get an exception list summary + description: Get a summary of the specified exception list. + parameters: + - name: id + in: query + required: false + description: Exception list's identifier generated upon creation + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListId' + - name: list_id + in: query + required: false + description: Exception list's human readable identifier + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionListHumanId' + - name: namespace_type + in: query + required: false + schema: + $ref: '../model/exception_list_common.schema.yaml#/components/schemas/ExceptionNamespaceType' + default: single + - name: filter + in: query + required: false + description: Search filter clause + schema: + type: string + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + windows: + type: integer + minimum: 0 + linux: + type: integer + minimum: 0 + macos: + type: integer + minimum: 0 + total: + type: integer + minimum: 0 + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: Exception list not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.gen.ts similarity index 79% rename from packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.gen.ts index 2f38661cc9587..fb5fde05dcc85 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.schema.yaml similarity index 77% rename from packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.schema.yaml index 5e8f3dfd8b509..0f7218a86c23f 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list/update_exception_list.schema.yaml @@ -59,29 +59,29 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 404: description: Exception list not found response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.gen.ts similarity index 86% rename from packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.gen.ts index 651c1dc1f2d49..791af5f65e35f 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.schema.yaml similarity index 77% rename from packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.schema.yaml index 2b8182aeb5c34..9adc75141f569 100644 --- a/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/update_exception_list_item/update_exception_list_item.schema.yaml @@ -70,32 +70,32 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 404: description: Exception list item not found response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: x-codegen-enabled: true @@ -104,9 +104,9 @@ components: type: object properties: id: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' comment: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' required: - comment diff --git a/packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml similarity index 100% rename from packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/docs/openapi/ess/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml diff --git a/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml similarity index 100% rename from packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml diff --git a/packages/kbn-securitysolution-exceptions-common/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-exceptions-common/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/package.json new file mode 100644 index 0000000000000..e68c27982b295 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/package.json @@ -0,0 +1,11 @@ +{ + "description": "Security Solution Exceptions common package", + "license": "Elastic License 2.0", + "name": "@kbn/securitysolution-exceptions-common", + "private": true, + "version": "1.0.0", + "scripts": { + "openapi:generate": "node scripts/openapi_generate", + "openapi:bundle": "node scripts/openapi_bundle" + } +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js new file mode 100644 index 0000000000000..996c55ce307d9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +require('../../../../../../src/setup_node_env'); +// eslint-disable-next-line import/no-nodejs-modules +const { join, resolve } = require('path'); +const { bundle } = require('@kbn/openapi-bundler'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/serverless/security_solution_exceptions_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['serverless'], + prototypeDocument: join(ROOT, 'scripts/openapi_bundle_info/exceptions_serverless.info.yaml'), + }, + }); + + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/ess/security_solution_exceptions_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['ess'], + prototypeDocument: join(ROOT, 'scripts/openapi_bundle_info/exceptions_ess.info.yaml'), + }, + }); +})(); diff --git a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle_info/exceptions_ess.info.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle_info/exceptions_ess.info.yaml similarity index 100% rename from packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle_info/exceptions_ess.info.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle_info/exceptions_ess.info.yaml diff --git a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle_info/exceptions_serverless.info.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle_info/exceptions_serverless.info.yaml similarity index 100% rename from packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle_info/exceptions_serverless.info.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle_info/exceptions_serverless.info.yaml diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js new file mode 100644 index 0000000000000..92488001b0b3a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js @@ -0,0 +1,51 @@ +/* + * 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. + */ + +require('../../../../../../src/setup_node_env'); +// eslint-disable-next-line import/no-nodejs-modules +const { join, resolve } = require('path'); +const { generate } = require('@kbn/openapi-generator'); +const { REPO_ROOT } = require('@kbn/repo-info'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await generate({ + title: 'OpenAPI Exceptions API Schemas', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'zod_operation_schema', + }); + + await generate({ + title: 'Exceptions API client for tests', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'api_client_supertest', + skipLinting: true, + bundle: { + outFile: join( + REPO_ROOT, + 'x-pack/test/api_integration/services/security_solution_exceptions_api.gen.ts' + ), + }, + }); + + await generate({ + title: 'Exceptions API client for quickstart', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'api_client_quickstart', + skipLinting: true, + bundle: { + outFile: join( + REPO_ROOT, + 'x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/api/quickstart_client.gen.ts' + ), + }, + }); +})(); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/tsconfig.json new file mode 100644 index 0000000000000..ba5a2c115a336 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "exclude": ["target/**/*"], + "extends": "../../../../../tsconfig.base.json", + "include": ["**/*.ts"], + "kbn_references": [ + "@kbn/openapi-common", + "@kbn/zod-helpers", + "@kbn/securitysolution-lists-common", + "@kbn/test", + "@kbn/tooling-log", + "@kbn/core-http-common", + "@kbn/securitysolution-utils", + "@kbn/zod", + ] +} diff --git a/packages/kbn-securitysolution-hook-utils/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/README.md similarity index 100% rename from packages/kbn-securitysolution-hook-utils/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/index.ts new file mode 100644 index 0000000000000..40ff03e880946 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +export * from './src/types'; +export * from './src/use_async'; +export * from './src/use_is_mounted'; +export * from './src/use_observable'; +export * from './src/with_optional_signal'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/jest.config.js b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/jest.config.js new file mode 100644 index 0000000000000..8238f9f7e97d2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils'], +}; diff --git a/packages/kbn-securitysolution-hook-utils/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-hook-utils/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/package.json new file mode 100644 index 0000000000000..efd415370f23d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/securitysolution-hook-utils", + "version": "1.0.0", + "description": "Security Solution utilities for React hooks", + "license": "Elastic License 2.0", + "private": true, + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/types.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/types.ts new file mode 100644 index 0000000000000..1b31cae2a16d4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/types.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +/** + * Represents the state of an asynchronous task, along with an initiator + * function to kick off the work. + */ +export interface Task { + loading: boolean; + error: unknown | undefined; + result: Result | undefined; + start: (...args: Args) => void; +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_async/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_async/index.test.ts new file mode 100644 index 0000000000000..e5420124a0ebc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_async/index.test.ts @@ -0,0 +1,164 @@ +/* + * 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 { waitFor, renderHook, act } from '@testing-library/react'; + +import { useAsync } from '.'; + +interface TestArgs { + n: number; + s: string; +} + +type TestReturn = Promise; + +describe('useAsync', () => { + /** + * Timeout for both jest tests and for the waitFor. + * jest tests default to 5 seconds and waitFor defaults to 1 second. + * 20_0000 = 20,000 milliseconds = 20 seconds + */ + const timeout = 20_000; + + let fn: jest.Mock; + let args: TestArgs; + + beforeEach(() => { + args = { n: 1, s: 's' }; + fn = jest.fn().mockResolvedValue(false); + }); + + it('does not invoke fn if start was not called', () => { + renderHook(() => useAsync(fn)); + expect(fn).not.toHaveBeenCalled(); + }); + + it( + 'invokes the function when start is called', + async () => { + const { result } = renderHook(() => useAsync(fn)); + + act(() => { + result.current.start(args); + }); + await waitFor(() => expect(fn).toHaveBeenCalled(), { timeout }); + }, + timeout + ); + + it('invokes the function with start args', async () => { + const { result } = renderHook(() => useAsync(fn)); + const expectedArgs = { ...args }; + + act(() => { + result.current.start(args); + }); + await waitFor(() => expect(fn).toHaveBeenCalledWith(expectedArgs), { timeout }); + }); + + it( + 'populates result with the resolved value of the fn', + async () => { + const { result } = renderHook(() => useAsync(fn)); + fn.mockResolvedValue({ resolved: 'value' }); + + act(() => { + result.current.start(args); + }); + await waitFor( + () => { + expect(result.current.result).toEqual({ resolved: 'value' }); + expect(result.current.error).toBeUndefined(); + }, + { timeout } + ); + }, + timeout + ); + + it( + 'populates error if function rejects', + async () => { + fn.mockRejectedValue(new Error('whoops')); + const { result } = renderHook(() => useAsync(fn)); + + act(() => { + result.current.start(args); + }); + + await waitFor( + () => { + expect(result.current.result).toBeUndefined(); + expect(result.current.error).toEqual(new Error('whoops')); + }, + { timeout } + ); + }, + timeout + ); + + it( + 'populates the loading state while the function is pending', + async () => { + let resolve: () => void; + fn.mockImplementation(() => new Promise((_resolve) => (resolve = _resolve))); + + const { result } = renderHook(() => useAsync(fn)); + + act(() => { + result.current.start(args); + }); + + expect(result.current.loading).toBe(true); + + act(() => resolve()); + await waitFor(() => expect(result.current.loading).toBe(false), { timeout }); + }, + timeout + ); + + it( + 'multiple start calls reset state', + async () => { + let resolve: (result: string) => void; + fn.mockImplementation(() => new Promise((_resolve) => (resolve = _resolve))); + + const { result } = renderHook(() => useAsync(fn)); + + act(() => { + result.current.start(args); + }); + + expect(result.current.loading).toBe(true); + + act(() => resolve('result')); + await waitFor( + () => { + expect(result.current.loading).toBe(false); + expect(result.current.result).toBe('result'); + }, + { timeout } + ); + + act(() => { + result.current.start(args); + }); + + expect(result.current.loading).toBe(true); + expect(result.current.result).toBe(undefined); + act(() => resolve('result')); + await waitFor( + () => { + expect(result.current.loading).toBe(false); + expect(result.current.result).toBe('result'); + }, + { timeout } + ); + }, + timeout + ); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_async/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_async/index.ts new file mode 100644 index 0000000000000..027039ac7cca7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_async/index.ts @@ -0,0 +1,54 @@ +/* + * 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 { useCallback, useState } from 'react'; + +import { Task } from '../types'; +import { useIsMounted } from '../use_is_mounted'; + +/** + * + * This hook wraps a promise-returning thunk (task) in order to conditionally + * initiate the work, and automatically provide state corresponding to the + * task's status. + * + * In order to function properly and not rerender unnecessarily, ensure that + * your task is a stable function reference. + * + * @param fn a function returning a promise. + * + * @returns An {@link Task} containing the task's current state along with a + * start callback + */ +export const useAsync = ( + fn: (...args: Args) => Promise +): Task => { + const isMounted = useIsMounted(); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(); + const [result, setResult] = useState(); + + const start = useCallback( + (...args: Args) => { + setLoading(true); + setResult(undefined); + setError(undefined); + fn(...args) + .then((r) => isMounted() && setResult(r)) + .catch((e) => isMounted() && setError(e)) + .finally(() => isMounted() && setLoading(false)); + }, + [fn, isMounted] + ); + + return { + error, + loading, + result, + start, + }; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.test.ts new file mode 100644 index 0000000000000..52f3a0739f4aa --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.test.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react'; + +import { useIsMounted } from '.'; + +describe('useIsMounted', () => { + it('evaluates to true when mounted', () => { + const { result } = renderHook(() => useIsMounted()); + + expect(result.current()).toEqual(true); + }); + + it('evaluates to false when unmounted', () => { + const { result, unmount } = renderHook(() => useIsMounted()); + + unmount(); + expect(result.current()).toEqual(false); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.ts new file mode 100644 index 0000000000000..8d325aed1abd6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_is_mounted/index.ts @@ -0,0 +1,29 @@ +/* + * 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 { useCallback, useEffect, useRef } from 'react'; + +type GetIsMounted = () => boolean; + +/** + * + * @returns A {@link GetIsMounted} getter function returning whether the component is currently mounted + */ +export const useIsMounted = (): GetIsMounted => { + const isMounted = useRef(false); + const getIsMounted: GetIsMounted = useCallback(() => isMounted.current, []); + const handleCleanup = useCallback(() => { + isMounted.current = false; + }, []); + + useEffect(() => { + isMounted.current = true; + return handleCleanup; + }, [handleCleanup]); + + return getIsMounted; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_observable/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_observable/index.test.ts new file mode 100644 index 0000000000000..3c6d96e3d3ac2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_observable/index.test.ts @@ -0,0 +1,159 @@ +/* + * 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 { renderHook, act } from '@testing-library/react'; +import { Subject, throwError } from 'rxjs'; + +import { useObservable } from '.'; + +interface TestArgs { + n: number; + s: string; +} + +type TestReturn = Subject; + +describe('useObservable', () => { + let fn: jest.Mock; + let subject: TestReturn; + let args: TestArgs; + + beforeEach(() => { + args = { n: 1, s: 's' }; + subject = new Subject(); + fn = jest.fn().mockReturnValue(subject); + }); + + it('does not invoke fn if start was not called', () => { + renderHook(() => useObservable(fn)); + expect(fn).not.toHaveBeenCalled(); + }); + + it('invokes the function when start is called', () => { + const { result } = renderHook(() => useObservable(fn)); + + act(() => { + result.current.start(args); + }); + + expect(fn).toHaveBeenCalled(); + }); + + it('invokes the function with start args', () => { + const { result } = renderHook(() => useObservable(fn)); + const expectedArgs = { ...args }; + + act(() => { + result.current.start(args); + }); + + expect(fn).toHaveBeenCalledWith(expectedArgs); + }); + + it('populates result with the next value of the fn', () => { + const { result } = renderHook(() => useObservable(fn)); + + act(() => { + result.current.start(args); + }); + act(() => subject.next('value')); + + expect(result.current.result).toEqual('value'); + expect(result.current.error).toBeUndefined(); + }); + + it('populates error if observable throws an error', () => { + const error = new Error('whoops'); + const errorFn = () => throwError(error); + + const { result } = renderHook(() => useObservable(errorFn)); + + act(() => { + result.current.start(); + }); + + expect(result.current.result).toBeUndefined(); + expect(result.current.error).toEqual(error); + }); + + it('populates the loading state while no value has resolved', () => { + const { result } = renderHook(() => useObservable(fn)); + + act(() => { + result.current.start(args); + }); + + expect(result.current.loading).toBe(true); + + act(() => subject.next('a value')); + + expect(result.current.loading).toBe(false); + }); + + it('updates result with each resolved value', () => { + const { result } = renderHook(() => useObservable(fn)); + + act(() => { + result.current.start(args); + }); + + act(() => subject.next('a value')); + expect(result.current.result).toEqual('a value'); + + act(() => subject.next('a subsequent value')); + expect(result.current.result).toEqual('a subsequent value'); + }); + + it('does not update result with values if start has not been called', () => { + const { result } = renderHook(() => useObservable(fn)); + + act(() => subject.next('a value')); + expect(result.current.result).toBeUndefined(); + + act(() => subject.next('a subsequent value')); + expect(result.current.result).toBeUndefined(); + }); + + it('unsubscribes on unmount', () => { + const { result, unmount } = renderHook(() => useObservable(fn)); + + act(() => { + result.current.start(args); + }); + expect(subject.observers).toHaveLength(1); + + unmount(); + expect(subject.observers).toHaveLength(0); + }); + + it('multiple start calls reset state', () => { + const { result } = renderHook(() => useObservable(fn)); + + act(() => { + result.current.start(args); + }); + + expect(result.current.loading).toBe(true); + + act(() => subject.next('one value')); + + expect(result.current.loading).toBe(false); + expect(result.current.result).toBe('one value'); + + act(() => { + result.current.start(args); + }); + + expect(result.current.loading).toBe(true); + expect(result.current.result).toBe(undefined); + + act(() => subject.next('another value')); + + expect(result.current.loading).toBe(false); + expect(result.current.result).toBe('another value'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_observable/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_observable/index.ts new file mode 100644 index 0000000000000..b7cd1e2623b78 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/use_observable/index.ts @@ -0,0 +1,91 @@ +/* + * 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 { useCallback, useEffect, useRef, useReducer, Reducer } from 'react'; +import { Observable, Subscription } from 'rxjs'; + +import { useIsMounted } from '../use_is_mounted'; +import { Task } from '../types'; + +interface State { + loading: boolean; + error?: unknown; + result?: T; +} + +export type Action = + | { type: 'setResult'; result: T } + | { type: 'setError'; error: unknown } + | { type: 'load' }; + +function reducer(state: State, action: Action) { + switch (action.type) { + case 'setResult': + return { ...state, result: action.result, loading: false }; + case 'setError': + return { ...state, error: action.error, loading: false }; + case 'load': + return { loading: true, result: undefined, error: undefined }; + } +} + +/** + * + * @param fn function returning an observable + * + * @returns An {@link Async} containing the underlying task's state along with a start callback + */ +export const useObservable = ( + fn: (...args: Args) => Observable +): Task => { + const isMounted = useIsMounted(); + const subRef = useRef(); + const [state, dispatch] = useReducer, Action>>(reducer, { + loading: false, + error: undefined, + result: undefined, + }); + + const start = useCallback( + (...args: Args) => { + if (subRef.current) { + subRef.current.unsubscribe(); + } + dispatch({ type: 'load' }); + + subRef.current = fn(...args).subscribe( + (r) => { + if (isMounted()) { + dispatch({ type: 'setResult', result: r }); + } + }, + (e) => { + if (isMounted()) { + dispatch({ type: 'setError', error: e }); + } + } + ); + }, + [fn, isMounted] + ); + + useEffect( + () => () => { + if (subRef.current) { + subRef.current.unsubscribe(); + } + }, + [] + ); + + return { + result: state.result, + error: state.error, + loading: state.loading, + start, + }; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.test.ts new file mode 100644 index 0000000000000..05a1b2fa167a0 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.test.ts @@ -0,0 +1,30 @@ +/* + * 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 { withOptionalSignal } from '.'; + +type TestFn = ({ number, signal }: { number: number; signal: AbortSignal }) => boolean; + +describe('withOptionalSignal', () => { + it('does not require a signal on the returned function', () => { + const fn = jest.fn().mockReturnValue('hello') as TestFn; + + const wrappedFn = withOptionalSignal(fn); + + expect(wrappedFn({ number: 1 })).toEqual('hello'); + }); + + it('will pass a given signal to the wrapped function', () => { + const fn = jest.fn().mockReturnValue('hello') as TestFn; + const { signal } = new AbortController(); + + const wrappedFn = withOptionalSignal(fn); + + wrappedFn({ number: 1, signal }); + expect(fn).toHaveBeenCalledWith({ number: 1, signal }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.ts new file mode 100644 index 0000000000000..eadad58804f83 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/src/with_optional_signal/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +interface SignalArgs { + signal: AbortSignal; +} + +export type OptionalSignalArgs = Omit & Partial; + +/** + * + * @param fn an async function receiving an AbortSignal argument + * + * @returns An async function where the AbortSignal argument is optional + */ +export const withOptionalSignal = + (fn: (args: Args) => Result) => + (args: OptionalSignalArgs): Result => { + const signal = args.signal != null ? args.signal : new AbortController().signal; + return fn({ ...args, signal } as Args); + }; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/tsconfig.json new file mode 100644 index 0000000000000..ccdf26c349f09 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-hook-utils/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/README.md similarity index 100% rename from packages/kbn-securitysolution-io-ts-alerting-types/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/index.ts new file mode 100644 index 0000000000000..f5e8f8419b254 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/index.ts @@ -0,0 +1,40 @@ +/* + * 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. + */ + +export * from './src/actions'; +export * from './src/default_actions_array'; +export * from './src/default_export_file_name'; +export * from './src/default_from_string'; +export * from './src/default_interval_string'; +export * from './src/default_language_string'; +export * from './src/default_max_signals_number'; +export * from './src/default_page'; +export * from './src/default_per_page'; +export * from './src/default_risk_score_mapping_array'; +export * from './src/default_severity_mapping_array'; +export * from './src/default_threat_array'; +export * from './src/default_to_string'; +export * from './src/default_uuid'; +export * from './src/frequency'; +export * from './src/language'; +export * from './src/machine_learning_job_id'; +export * from './src/max_signals'; +export * from './src/normalized_ml_job_id'; +export * from './src/references_default_array'; +export * from './src/risk_score'; +export * from './src/risk_score_mapping'; +export * from './src/rule_schedule'; +export * from './src/saved_object_attributes'; +export * from './src/severity'; +export * from './src/severity_mapping'; +export * from './src/threat'; +export * from './src/threat_mapping'; +export * from './src/threat_subtechnique'; +export * from './src/threat_tactic'; +export * from './src/threat_technique'; +export * from './src/throttle'; +export * from './src/type'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/jest.config.js b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/jest.config.js new file mode 100644 index 0000000000000..16223422cbd8d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types'], +}; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-io-ts-alerting-types/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/package.json new file mode 100644 index 0000000000000..bbe6c163fb5e8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/securitysolution-io-ts-alerting-types", + "version": "1.0.0", + "description": "io ts utilities and types to be shared with plugins from the security solution project", + "license": "Elastic License 2.0", + "private": true, + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts new file mode 100644 index 0000000000000..64953a0dc0cdd --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts @@ -0,0 +1,127 @@ +/* + * 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 { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +import * as t from 'io-ts'; +import { saved_object_attributes } from '../saved_object_attributes'; +import { RuleActionFrequency } from '../frequency'; + +export type RuleActionGroup = t.TypeOf; +export const RuleActionGroup = t.string; + +export type RuleActionId = t.TypeOf; +export const RuleActionId = t.string; + +export type RuleActionTypeId = t.TypeOf; +export const RuleActionTypeId = t.string; + +export type RuleActionUuid = t.TypeOf; +export const RuleActionUuid = NonEmptyString; + +/** + * Params is an "object", since it is a type of RuleActionParams which is action templates. + * @see x-pack/plugins/alerting/common/rule.ts + */ +export type RuleActionParams = t.TypeOf; +export const RuleActionParams = saved_object_attributes; + +export const RuleActionAlertsFilter = t.partial({ + query: t.union([ + t.undefined, + t.intersection([ + t.strict({ + kql: t.string, + filters: t.array( + t.intersection([ + t.type({ + meta: t.partial({ + alias: t.union([t.string, t.null]), + disabled: t.boolean, + negate: t.boolean, + controlledBy: t.string, + group: t.string, + index: t.string, + isMultiIndex: t.boolean, + type: t.string, + key: t.string, + params: t.any, + value: t.string, + }), + }), + t.partial({ + $state: t.type({ store: t.any }), + query: t.record(t.string, t.any), + }), + ]) + ), + }), + t.partial({ dsl: t.string }), + ]), + ]), + timeframe: t.union([ + t.undefined, + t.strict({ + timezone: t.string, + days: t.array( + t.union([ + t.literal(1), + t.literal(2), + t.literal(3), + t.literal(4), + t.literal(5), + t.literal(6), + t.literal(7), + ]) + ), + hours: t.strict({ + start: t.string, + end: t.string, + }), + }), + ]), +}); + +export type RuleAction = t.TypeOf; +export const RuleAction = t.exact( + t.intersection([ + t.type({ + group: RuleActionGroup, + id: RuleActionId, + action_type_id: RuleActionTypeId, + params: RuleActionParams, + }), + t.partial({ + uuid: RuleActionUuid, + alerts_filter: RuleActionAlertsFilter, + frequency: RuleActionFrequency, + }), + ]) +); + +export type RuleActionArray = t.TypeOf; +export const RuleActionArray = t.array(RuleAction); + +export type RuleActionCamel = t.TypeOf; +export const RuleActionCamel = t.exact( + t.intersection([ + t.type({ + group: RuleActionGroup, + id: RuleActionId, + actionTypeId: RuleActionTypeId, + params: RuleActionParams, + }), + t.partial({ + uuid: RuleActionUuid, + alertsFilter: RuleActionAlertsFilter, + frequency: RuleActionFrequency, + }), + ]) +); + +export type RuleActionArrayCamel = t.TypeOf; +export const RuleActionArrayCamel = t.array(RuleActionCamel); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.mock.ts new file mode 100644 index 0000000000000..2747846c74d80 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const ENTRY_VALUE = 'some host name'; +export const FIELD = 'host.name'; +export const MATCH = 'match'; +export const MATCH_ANY = 'match_any'; +export const OPERATOR = 'included'; +export const NESTED = 'nested'; +export const NESTED_FIELD = 'parent.field'; +export const LIST_ID = 'some-list-id'; +export const LIST = 'list'; +export const TYPE = 'ip'; +export const EXISTS = 'exists'; +export const WILDCARD = 'wildcard'; +export const USER = 'some user'; +export const DATE_NOW = '2020-04-20T15:25:31.830Z'; + +// Exception List specific +export const ID = 'uuid_here'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts new file mode 100644 index 0000000000000..ad5a2ba262260 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +/** + * TODO: Create a kbn-alerting-constants and add this to it. + * @deprecated Use a DEFAULT_MAX_SIGNALS from a kbn-alerting-constants package. + */ +export const DEFAULT_MAX_SIGNALS = 100; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts new file mode 100644 index 0000000000000..28ff3053564c9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_actions_array/index.ts @@ -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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { RuleActionArray } from '../actions'; + +export const DefaultActionsArray = new t.Type< + RuleActionArray, + RuleActionArray | undefined, + unknown +>( + 'DefaultActionsArray', + RuleActionArray.is, + (input, context): Either => + input == null ? t.success([]) : RuleActionArray.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.test.ts new file mode 100644 index 0000000000000..009fdb23d3fb7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.test.ts @@ -0,0 +1,42 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultExportFileName } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_export_file_name', () => { + test('it should validate a regular string', () => { + const payload = 'some string'; + const decoded = DefaultExportFileName.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate a number', () => { + const payload = 5; + const decoded = DefaultExportFileName.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "DefaultExportFileName"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default of "export.ndjson"', () => { + const payload = null; + const decoded = DefaultExportFileName.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual('export.ndjson'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.ts new file mode 100644 index 0000000000000..53f0972baca21 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_export_file_name/index.ts @@ -0,0 +1,21 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; + +/** + * Types the DefaultExportFileName as: + * - If null or undefined, then a default of "export.ndjson" will be used + */ +export const DefaultExportFileName = new t.Type( + 'DefaultExportFileName', + t.string.is, + (input, context): Either => + input == null ? t.success('export.ndjson') : t.string.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.test.ts new file mode 100644 index 0000000000000..f6c7f91e315ad --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.test.ts @@ -0,0 +1,42 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultFromString } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_from_string', () => { + test('it should validate a from string', () => { + const payload = 'now-20m'; + const decoded = DefaultFromString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate a number', () => { + const payload = 5; + const decoded = DefaultFromString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "DefaultFromString"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default of "now-6m"', () => { + const payload = null; + const decoded = DefaultFromString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual('now-6m'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts new file mode 100644 index 0000000000000..d23bca135d03e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_from_string/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { From } from '../from'; + +/** + * Types the DefaultFromString as: + * - If null or undefined, then a default of the string "now-6m" will be used + */ +export const DefaultFromString = new t.Type( + 'DefaultFromString', + t.string.is, + (input, context): Either => { + if (input == null) { + return t.success('now-6m'); + } + return From.validate(input, context); + }, + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.test.ts new file mode 100644 index 0000000000000..602d6c9ff79e8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.test.ts @@ -0,0 +1,42 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultIntervalString } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_interval_string', () => { + test('it should validate a interval string', () => { + const payload = '20m'; + const decoded = DefaultIntervalString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate a number', () => { + const payload = 5; + const decoded = DefaultIntervalString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "DefaultIntervalString"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default of "5m"', () => { + const payload = null; + const decoded = DefaultIntervalString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual('5m'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.ts new file mode 100644 index 0000000000000..d743fa773f2ec --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_interval_string/index.ts @@ -0,0 +1,21 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; + +/** + * Types the DefaultIntervalString as: + * - If null or undefined, then a default of the string "5m" will be used + */ +export const DefaultIntervalString = new t.Type( + 'DefaultIntervalString', + t.string.is, + (input, context): Either => + input == null ? t.success('5m') : t.string.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.test.ts new file mode 100644 index 0000000000000..34e6e65518c71 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.test.ts @@ -0,0 +1,43 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { Language } from '../language'; +import { DefaultLanguageString } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_language_string', () => { + test('it should validate a string', () => { + const payload: Language = 'lucene'; + const decoded = DefaultLanguageString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate a number', () => { + const payload = 5; + const decoded = DefaultLanguageString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "DefaultLanguageString"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default of "kuery"', () => { + const payload = null; + const decoded = DefaultLanguageString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual('kuery'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.ts new file mode 100644 index 0000000000000..ca557dafecefd --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_language_string/index.ts @@ -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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { language } from '../language'; + +/** + * Types the DefaultLanguageString as: + * - If null or undefined, then a default of the string "kuery" will be used + */ +export const DefaultLanguageString = new t.Type( + 'DefaultLanguageString', + t.string.is, + (input, context): Either => + input == null ? t.success('kuery') : language.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.test.ts new file mode 100644 index 0000000000000..cd4b0aa42953b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.test.ts @@ -0,0 +1,65 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultMaxSignalsNumber } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { DEFAULT_MAX_SIGNALS } from '../constants'; + +describe('default_from_string', () => { + test('it should validate a max signal number', () => { + const payload = 5; + const decoded = DefaultMaxSignalsNumber.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate a string', () => { + const payload = '5'; + const decoded = DefaultMaxSignalsNumber.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "DefaultMaxSignals"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not validate a zero', () => { + const payload = 0; + const decoded = DefaultMaxSignalsNumber.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "0" supplied to "DefaultMaxSignals"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not validate a negative number', () => { + const payload = -1; + const decoded = DefaultMaxSignalsNumber.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "-1" supplied to "DefaultMaxSignals"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default of DEFAULT_MAX_SIGNALS', () => { + const payload = null; + const decoded = DefaultMaxSignalsNumber.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(DEFAULT_MAX_SIGNALS); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.ts new file mode 100644 index 0000000000000..535f9397c7afb --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_max_signals_number/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { max_signals } from '../max_signals'; +import { DEFAULT_MAX_SIGNALS } from '../constants'; + +/** + * Types the default max signal: + * - Natural Number (positive integer and not a float), + * - greater than 1 + * - If undefined then it will use DEFAULT_MAX_SIGNALS (100) as the default + */ +export const DefaultMaxSignalsNumber = new t.Type( + 'DefaultMaxSignals', + t.number.is, + (input, context): Either => { + return input == null ? t.success(DEFAULT_MAX_SIGNALS) : max_signals.validate(input, context); + }, + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.test.ts new file mode 100644 index 0000000000000..d9e63e0f9ec14 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.test.ts @@ -0,0 +1,84 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultPage } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_page', () => { + test('it should validate a regular number greater than zero', () => { + const payload = 5; + const decoded = DefaultPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate a string of a number', () => { + const payload = '5'; + const decoded = DefaultPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(5); + }); + + test('it should not validate a junk string', () => { + const payload = 'invalid-string'; + const decoded = DefaultPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "NaN" supplied to "DefaultPerPage"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not validate an empty string', () => { + const payload = ''; + const decoded = DefaultPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "NaN" supplied to "DefaultPerPage"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not validate a zero', () => { + const payload = 0; + const decoded = DefaultPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "0" supplied to "DefaultPerPage"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not validate a negative number', () => { + const payload = -1; + const decoded = DefaultPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "-1" supplied to "DefaultPerPage"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default of 20', () => { + const payload = null; + const decoded = DefaultPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(1); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.ts new file mode 100644 index 0000000000000..6ae23dd8c676f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_page/index.ts @@ -0,0 +1,31 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; + +/** + * Types the DefaultPerPage as: + * - If a string this will convert the string to a number + * - If null or undefined, then a default of 1 will be used + * - If the number is 0 or less this will not validate as it has to be a positive number greater than zero + */ +export const DefaultPage = new t.Type( + 'DefaultPerPage', + t.number.is, + (input, context): Either => { + if (input == null) { + return t.success(1); + } else if (typeof input === 'string') { + return PositiveIntegerGreaterThanZero.validate(parseInt(input, 10), context); + } else { + return PositiveIntegerGreaterThanZero.validate(input, context); + } + }, + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.test.ts new file mode 100644 index 0000000000000..07a6358ba2e89 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.test.ts @@ -0,0 +1,84 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultPerPage } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_per_page', () => { + test('it should validate a regular number greater than zero', () => { + const payload = 5; + const decoded = DefaultPerPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate a string of a number', () => { + const payload = '5'; + const decoded = DefaultPerPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(5); + }); + + test('it should not validate a junk string', () => { + const payload = 'invalid-string'; + const decoded = DefaultPerPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "NaN" supplied to "DefaultPerPage"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not validate an empty string', () => { + const payload = ''; + const decoded = DefaultPerPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "NaN" supplied to "DefaultPerPage"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not validate a zero', () => { + const payload = 0; + const decoded = DefaultPerPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "0" supplied to "DefaultPerPage"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not validate a negative number', () => { + const payload = -1; + const decoded = DefaultPerPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "-1" supplied to "DefaultPerPage"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default of 20', () => { + const payload = null; + const decoded = DefaultPerPage.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(20); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.ts new file mode 100644 index 0000000000000..320945311d3b6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_per_page/index.ts @@ -0,0 +1,31 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; + +/** + * Types the DefaultPerPage as: + * - If a string this will convert the string to a number + * - If null or undefined, then a default of 20 will be used + * - If the number is 0 or less this will not validate as it has to be a positive number greater than zero + */ +export const DefaultPerPage = new t.Type( + 'DefaultPerPage', + t.number.is, + (input, context): Either => { + if (input == null) { + return t.success(20); + } else if (typeof input === 'string') { + return PositiveIntegerGreaterThanZero.validate(parseInt(input, 10), context); + } else { + return PositiveIntegerGreaterThanZero.validate(input, context); + } + }, + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts new file mode 100644 index 0000000000000..a457c827e25f6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_risk_score_mapping_array/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { RiskScoreMapping } from '../risk_score_mapping'; + +/** + * Types the DefaultStringArray as: + * - If null or undefined, then a default RiskScoreMapping array will be set + */ +export const DefaultRiskScoreMappingArray = new t.Type< + RiskScoreMapping, + RiskScoreMapping | undefined, + unknown +>( + 'DefaultRiskScoreMappingArray', + RiskScoreMapping.is, + (input, context): Either => + input == null ? t.success([]) : RiskScoreMapping.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts new file mode 100644 index 0000000000000..8d7b581146eac --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_severity_mapping_array/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { SeverityMapping } from '../severity_mapping'; + +/** + * Types the DefaultStringArray as: + * - If null or undefined, then a default SeverityMapping array will be set + */ +export const DefaultSeverityMappingArray = new t.Type< + SeverityMapping, + SeverityMapping | undefined, + unknown +>( + 'DefaultSeverityMappingArray', + SeverityMapping.is, + (input, context): Either => + input == null ? t.success([]) : SeverityMapping.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.test.ts new file mode 100644 index 0000000000000..ed42de41effcc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.test.ts @@ -0,0 +1,65 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { Threats } from '../threat'; +import { DefaultThreatArray } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_threat_null', () => { + test('it should validate an empty array', () => { + const payload: Threats = []; + const decoded = DefaultThreatArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of threats', () => { + const payload: Threats = [ + { + framework: 'MITRE ATTACK', + technique: [{ reference: 'https://test.com', name: 'Audio Capture', id: 'T1123' }], + tactic: { reference: 'https://test.com', name: 'Collection', id: 'TA000999' }, + }, + ]; + const decoded = DefaultThreatArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate an array with a number', () => { + const payload = [ + { + framework: 'MITRE ATTACK', + technique: [{ reference: 'https://test.com', name: 'Audio Capture', id: 'T1123' }], + tactic: { reference: 'https://test.com', name: 'Collection', id: 'TA000999' }, + }, + 5, + ]; + const decoded = DefaultThreatArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "DefaultThreatArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default empty array if not provided a value', () => { + const payload = null; + const decoded = DefaultThreatArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([]); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.ts new file mode 100644 index 0000000000000..8ed8abc587504 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_threat_array/index.ts @@ -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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { threats, Threats } from '../threat'; + +/** + * Types the DefaultThreatArray as: + * - If null or undefined, then an empty array will be set + */ +export const DefaultThreatArray = new t.Type( + 'DefaultThreatArray', + threats.is, + (input, context): Either => + input == null ? t.success([]) : threats.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.test.ts new file mode 100644 index 0000000000000..f87b1c4f24a9e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.test.ts @@ -0,0 +1,42 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultToString } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_to_string', () => { + test('it should validate a to string', () => { + const payload = 'now-5m'; + const decoded = DefaultToString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate a number', () => { + const payload = 5; + const decoded = DefaultToString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "DefaultToString"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default of "now"', () => { + const payload = null; + const decoded = DefaultToString.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual('now'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.ts new file mode 100644 index 0000000000000..d2e58f423b592 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_to_string/index.ts @@ -0,0 +1,21 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; + +/** + * Types the DefaultToString as: + * - If null or undefined, then a default of the string "now" will be used + */ +export const DefaultToString = new t.Type( + 'DefaultToString', + t.string.is, + (input, context): Either => + input == null ? t.success('now') : t.string.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.test.ts new file mode 100644 index 0000000000000..ee605a5c4383a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.test.ts @@ -0,0 +1,42 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultUuid } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_uuid', () => { + test('it should validate a regular string', () => { + const payload = '1'; + const decoded = DefaultUuid.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate a number', () => { + const payload = 5; + const decoded = DefaultUuid.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "DefaultUuid"']); + expect(message.schema).toEqual({}); + }); + + test('it should return a default of a uuid', () => { + const payload = null; + const decoded = DefaultUuid.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i + ); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.ts new file mode 100644 index 0000000000000..b3d6fda5b134a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/default_uuid/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { v4 as uuidv4 } from 'uuid'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +/** + * Types the DefaultUuid as: + * - If null or undefined, then a default string uuidv4() will be + * created otherwise it will be checked just against an empty string + */ +export const DefaultUuid = new t.Type( + 'DefaultUuid', + t.string.is, + (input, context): Either => + input == null ? t.success(uuidv4()) : NonEmptyString.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/frequency/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/frequency/index.ts new file mode 100644 index 0000000000000..318408f145823 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/frequency/index.ts @@ -0,0 +1,36 @@ +/* + * 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 * as t from 'io-ts'; + +import { RuleActionThrottle } from '../throttle'; + +/** + * Action summary indicates whether we will send a summary notification about all the generate alerts or notification per individual alert + */ +export type RuleActionSummary = t.TypeOf; +export const RuleActionSummary = t.boolean; + +/** + * The condition for throttling the notification: `onActionGroupChange`, `onActiveAlert`, or `onThrottleInterval` + */ +export type RuleActionNotifyWhen = t.TypeOf; +export const RuleActionNotifyWhen = t.union([ + t.literal('onActionGroupChange'), + t.literal('onActiveAlert'), + t.literal('onThrottleInterval'), +]); + +/** + * The action frequency defines when the action runs (for example, only on rule execution or at specific time intervals). + */ +export type RuleActionFrequency = t.TypeOf; +export const RuleActionFrequency = t.type({ + summary: RuleActionSummary, + notifyWhen: RuleActionNotifyWhen, + throttle: t.union([RuleActionThrottle, t.null]), +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts new file mode 100644 index 0000000000000..d0330fae61404 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Either } from 'fp-ts/lib/Either'; +import * as t from 'io-ts'; +import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; + +const stringValidator = (input: unknown): input is string => typeof input === 'string'; + +export type From = t.TypeOf; +export const From = new t.Type( + 'From', + t.string.is, + (input, context): Either => { + if (stringValidator(input) && parseScheduleDates(input) == null) { + return t.failure(input, context, 'Failed to parse "from" on rule param'); + } + return t.string.validate(input, context); + }, + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts new file mode 100644 index 0000000000000..63ad102a41349 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/language/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const language = t.keyof({ eql: null, kuery: null, lucene: null, esql: null }); +export type Language = t.TypeOf; + +export const languageOrUndefined = t.union([language, t.undefined]); +export type LanguageOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts new file mode 100644 index 0000000000000..8e6453ac7e7b8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/machine_learning_job_id/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +import { machine_learning_job_id_normalized } from '../normalized_ml_job_id'; + +export const machine_learning_job_id = t.union([t.string, machine_learning_job_id_normalized]); +export type MachineLearningJobId = t.TypeOf; + +export const machineLearningJobIdOrUndefined = t.union([machine_learning_job_id, t.undefined]); +export type MachineLearningJobIdOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts new file mode 100644 index 0000000000000..64ded4827b5eb --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/max_signals/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; +import { PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; + +export const max_signals = PositiveIntegerGreaterThanZero; +export type MaxSignals = t.TypeOf; + +export const maxSignalsOrUndefined = t.union([max_signals, t.undefined]); +export type MaxSignalsOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts new file mode 100644 index 0000000000000..f81c3da1db5d2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/normalized_ml_job_id/index.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +import { NonEmptyArray } from '@kbn/securitysolution-io-ts-types'; + +export const machine_learning_job_id_normalized = NonEmptyArray(t.string); +export type MachineLearningJobIdNormalized = t.TypeOf; + +export const machineLearningJobIdNormalizedOrUndefined = t.union([ + machine_learning_job_id_normalized, + t.undefined, +]); +export type MachineLearningJobIdNormalizedOrUndefined = t.TypeOf< + typeof machineLearningJobIdNormalizedOrUndefined +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.test.ts new file mode 100644 index 0000000000000..7c5e9bb29877f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.test.ts @@ -0,0 +1,51 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { ReferencesDefaultArray } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_string_array', () => { + test('it should validate an empty array', () => { + const payload: string[] = []; + const decoded = ReferencesDefaultArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of strings', () => { + const payload = ['value 1', 'value 2']; + const decoded = ReferencesDefaultArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate an array with a number', () => { + const payload = ['value 1', 5]; + const decoded = ReferencesDefaultArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "referencesWithDefaultArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default array entry', () => { + const payload = null; + const decoded = ReferencesDefaultArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([]); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.ts new file mode 100644 index 0000000000000..e5ccac3650434 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/references_default_array/index.ts @@ -0,0 +1,21 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; + +/** + * Types the ReferencesDefaultArray as: + * - If null or undefined, then a default array will be set + */ +export const ReferencesDefaultArray = new t.Type( + 'referencesWithDefaultArray', + t.array(t.string).is, + (input, context): Either => + input == null ? t.success([]) : t.array(t.string).validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.test.ts new file mode 100644 index 0000000000000..b55ef415fbbb5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.test.ts @@ -0,0 +1,60 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { RiskScore } from '.'; + +describe('risk_score', () => { + test('it should validate a positive number', () => { + const payload = 1; + const decoded = RiskScore.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate a zero', () => { + const payload = 0; + const decoded = RiskScore.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT validate a negative number', () => { + const payload = -1; + const decoded = RiskScore.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "-1" supplied to "RiskScore"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT validate a string', () => { + const payload = 'some string'; + const decoded = RiskScore.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "some string" supplied to "RiskScore"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT validate a risk score greater than 100', () => { + const payload = 101; + const decoded = RiskScore.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "101" supplied to "RiskScore"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts new file mode 100644 index 0000000000000..143ea2e727543 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; + +/** + * Types the risk score as: + * - Natural Number (positive integer and not a float), + * - Between the values [0 and 100] inclusive. + */ +export type RiskScore = t.TypeOf; +export const RiskScore = new t.Type( + 'RiskScore', + t.number.is, + (input, context): Either => { + return typeof input === 'number' && Number.isSafeInteger(input) && input >= 0 && input <= 100 + ? t.success(input) + : t.failure(input, context); + }, + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts new file mode 100644 index 0000000000000..0856806d48989 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/risk_score_mapping/index.ts @@ -0,0 +1,23 @@ +/* + * 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 * as t from 'io-ts'; +import { operator } from '@kbn/securitysolution-io-ts-types'; +import { RiskScore } from '../risk_score'; + +export type RiskScoreMappingItem = t.TypeOf; +export const RiskScoreMappingItem = t.exact( + t.type({ + field: t.string, + value: t.string, + operator, + risk_score: t.union([RiskScore, t.undefined]), + }) +); + +export type RiskScoreMapping = t.TypeOf; +export const RiskScoreMapping = t.array(RiskScoreMappingItem); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts new file mode 100644 index 0000000000000..16bc6dc153104 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/rule_schedule/index.ts @@ -0,0 +1,21 @@ +/* + * 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 * as t from 'io-ts'; +import { From } from '../from'; + +export type RuleInterval = t.TypeOf; +export const RuleInterval = t.string; // we need a more specific schema + +export type RuleIntervalFrom = t.TypeOf; +export const RuleIntervalFrom = From; + +/** + * TODO: Create a regular expression type or custom date math part type here + */ +export type RuleIntervalTo = t.TypeOf; +export const RuleIntervalTo = t.string; // we need a more specific schema diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/saved_object_attributes/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/saved_object_attributes/index.ts new file mode 100644 index 0000000000000..33db222f098e1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/saved_object_attributes/index.ts @@ -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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +/** + * TODO: This type are originally from "src/core/types/saved_objects.ts", once that is package friendly remove + * this copied type. + * + * Don't use this type, it's simply a helper type for {@link SavedObjectAttribute} + * + * @public + */ +export type SavedObjectAttributeSingle = + | string + | number + | boolean + | null + | undefined + | SavedObjectAttributes; + +/** + * TODO: This type are originally from "src/core/types/saved_objects.ts", once that is package friendly remove + * this copied type. + * + * Type definition for a Saved Object attribute value + * + * @public + */ +export type SavedObjectAttribute = SavedObjectAttributeSingle | SavedObjectAttributeSingle[]; + +/** + * TODO: This type are originally from "src/core/types/saved_objects.ts", once that is package friendly remove + * this copied type. + * + * The data for a Saved Object is stored as an object in the `attributes` + * property. + * + * @public + */ +export interface SavedObjectAttributes { + [key: string]: SavedObjectAttribute; +} + +export const saved_object_attribute_single: t.Type = t.recursion( + 'saved_object_attribute_single', + () => t.union([t.string, t.number, t.boolean, t.null, t.undefined, saved_object_attributes]) +); +export const saved_object_attribute: t.Type = t.recursion( + 'saved_object_attribute', + () => t.union([saved_object_attribute_single, t.array(saved_object_attribute_single)]) +); +export const saved_object_attributes: t.Type = t.recursion( + 'saved_object_attributes', + () => t.record(t.string, saved_object_attribute) +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts new file mode 100644 index 0000000000000..1b27423eb0dba --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/severity/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export type Severity = t.TypeOf; +export const Severity = t.keyof({ low: null, medium: null, high: null, critical: null }); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts new file mode 100644 index 0000000000000..4256314b32a2c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/severity_mapping/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +import { operator } from '@kbn/securitysolution-io-ts-types'; +import { Severity } from '../severity'; + +export type SeverityMappingItem = t.TypeOf; +export const SeverityMappingItem = t.exact( + t.type({ + field: t.string, + operator, + value: t.string, + severity: Severity, + }) +); + +export type SeverityMapping = t.TypeOf; +export const SeverityMapping = t.array(SeverityMappingItem); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat/index.ts new file mode 100644 index 0000000000000..4b5b7aa16c2dc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat/index.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; +import { threat_tactic } from '../threat_tactic'; +import { threat_techniques } from '../threat_technique'; + +export const threat_framework = t.string; + +export const threat = t.intersection([ + t.exact( + t.type({ + framework: threat_framework, + tactic: threat_tactic, + }) + ), + t.exact( + t.partial({ + technique: threat_techniques, + }) + ), +]); + +export type Threat = t.TypeOf; + +export const threats = t.array(threat); +export type Threats = t.TypeOf; + +export const threatsOrUndefined = t.union([threats, t.undefined]); +export type ThreatsOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.test.ts new file mode 100644 index 0000000000000..781b5b89ebe6c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.test.ts @@ -0,0 +1,235 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { + concurrent_searches, + items_per_search, + ThreatMapping, + threatMappingEntries, + ThreatMappingEntries, + threat_mapping, +} from '.'; +import { foldLeftRight, getPaths, exactCheck } from '@kbn/securitysolution-io-ts-utils'; + +describe('threat_mapping', () => { + describe('threatMappingEntries', () => { + test('it should validate an entry', () => { + const payload: ThreatMappingEntries = [ + { + field: 'field.one', + type: 'mapping', + value: 'field.one', + }, + ]; + const decoded = threatMappingEntries.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation with an extra entry item', () => { + const payload: Array = [ + { + field: 'field.one', + type: 'mapping', + value: 'field.one', + extra: 'blah', + }, + ]; + const decoded = threatMappingEntries.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extra"']); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation with a non string', () => { + const payload = [ + { + field: 5, + type: 'mapping', + value: 'field.one', + }, + ] as unknown as ThreatMappingEntries[]; + const decoded = threatMappingEntries.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation with a wrong type', () => { + const payload = [ + { + field: 'field.one', + type: 'invalid', + value: 'field.one', + }, + ] as unknown as ThreatMappingEntries[]; + const decoded = threatMappingEntries.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "invalid" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + }); + + describe('threat_mapping', () => { + test('it should validate a threat mapping', () => { + const payload: ThreatMapping = [ + { + entries: [ + { + field: 'field.one', + type: 'mapping', + value: 'field.one', + }, + ], + }, + ]; + const decoded = threat_mapping.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + }); + + test('it should fail validate with an extra key', () => { + const payload: Array = [ + { + entries: [ + { + field: 'field.one', + type: 'mapping', + value: 'field.one', + }, + ], + extra: 'invalid', + }, + ]; + + const decoded = threat_mapping.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extra"']); + expect(message.schema).toEqual({}); + }); + + test('it should fail validate with an extra inner entry', () => { + const payload: Array }> = [ + { + entries: [ + { + field: 'field.one', + type: 'mapping', + value: 'field.one', + extra: 'blah', + }, + ], + }, + ]; + + const decoded = threat_mapping.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extra"']); + expect(message.schema).toEqual({}); + }); + + test('it should fail validate with an extra inner entry with the wrong data type', () => { + const payload = [ + { + entries: [ + { + field: 5, + type: 'mapping', + value: 'field.one', + }, + ], + }, + ] as unknown as ThreatMapping; + + const decoded = threat_mapping.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "entries,field"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validate with empty array', () => { + const payload: string[] = []; + + const decoded = threat_mapping.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "[]" supplied to "NonEmptyArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when concurrent_searches is < 0', () => { + const payload = -1; + const decoded = concurrent_searches.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "-1" supplied to "PositiveIntegerGreaterThanZero"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when concurrent_searches is 0', () => { + const payload = 0; + const decoded = concurrent_searches.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "0" supplied to "PositiveIntegerGreaterThanZero"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when items_per_search is 0', () => { + const payload = 0; + const decoded = items_per_search.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "0" supplied to "PositiveIntegerGreaterThanZero"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when items_per_search is < 0', () => { + const payload = -1; + const decoded = items_per_search.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "-1" supplied to "PositiveIntegerGreaterThanZero"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts new file mode 100644 index 0000000000000..3bf4f84aeec8e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_mapping/index.ts @@ -0,0 +1,77 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; +import { + NonEmptyArray, + NonEmptyString, + PositiveIntegerGreaterThanZero, +} from '@kbn/securitysolution-io-ts-types'; +import { language } from '../language'; + +export const threat_query = t.string; +export type ThreatQuery = t.TypeOf; +export const threatQueryOrUndefined = t.union([threat_query, t.undefined]); +export type ThreatQueryOrUndefined = t.TypeOf; + +export const threat_indicator_path = t.string; +export type ThreatIndicatorPath = t.TypeOf; +export const threatIndicatorPathOrUndefined = t.union([threat_indicator_path, t.undefined]); +export type ThreatIndicatorPathOrUndefined = t.TypeOf; + +export const threat_filters = t.array(t.unknown); // Filters are not easily type-able yet +export type ThreatFilters = t.TypeOf; +export const threatFiltersOrUndefined = t.union([threat_filters, t.undefined]); +export type ThreatFiltersOrUndefined = t.TypeOf; + +export const threatMapEntry = t.exact( + t.type({ + field: NonEmptyString, + type: t.keyof({ mapping: null }), + value: NonEmptyString, + }) +); + +export type ThreatMapEntry = t.TypeOf; + +export const threatMappingEntries = t.array(threatMapEntry); +export type ThreatMappingEntries = t.TypeOf; + +export const threatMap = t.exact( + t.type({ + entries: threatMappingEntries, + }) +); +export type ThreatMap = t.TypeOf; + +export const threat_mapping = NonEmptyArray(threatMap, 'NonEmptyArray'); +export type ThreatMapping = t.TypeOf; + +export const threatMappingOrUndefined = t.union([threat_mapping, t.undefined]); +export type ThreatMappingOrUndefined = t.TypeOf; + +export const threat_index = t.array(t.string); +export type ThreatIndex = t.TypeOf; +export const threatIndexOrUndefined = t.union([threat_index, t.undefined]); +export type ThreatIndexOrUndefined = t.TypeOf; + +export const threat_language = t.union([language, t.undefined]); +export type ThreatLanguage = t.TypeOf; +export const threatLanguageOrUndefined = t.union([threat_language, t.undefined]); +export type ThreatLanguageOrUndefined = t.TypeOf; + +export const concurrent_searches = PositiveIntegerGreaterThanZero; +export type ConcurrentSearches = t.TypeOf; +export const concurrentSearchesOrUndefined = t.union([concurrent_searches, t.undefined]); +export type ConcurrentSearchesOrUndefined = t.TypeOf; + +export const items_per_search = PositiveIntegerGreaterThanZero; +export type ItemsPerSearch = t.TypeOf; +export const itemsPerSearchOrUndefined = t.union([items_per_search, t.undefined]); +export type ItemsPerSearchOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_subtechnique/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_subtechnique/index.ts new file mode 100644 index 0000000000000..b5f2d95a139b5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_subtechnique/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const threat_subtechnique_id = t.string; +export const threat_subtechnique_name = t.string; +export const threat_subtechnique_reference = t.string; + +export const threat_subtechnique = t.type({ + id: threat_subtechnique_id, + name: threat_subtechnique_name, + reference: threat_subtechnique_reference, +}); + +export const threat_subtechniques = t.array(threat_subtechnique); + +export type ThreatSubtechnique = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_tactic/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_tactic/index.ts new file mode 100644 index 0000000000000..a4c63cb632892 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_tactic/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const threat_tactic_id = t.string; +export const threat_tactic_name = t.string; +export const threat_tactic_reference = t.string; + +export const threat_tactic = t.type({ + id: threat_tactic_id, + name: threat_tactic_name, + reference: threat_tactic_reference, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_technique/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_technique/index.ts new file mode 100644 index 0000000000000..992c5b15ba655 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/threat_technique/index.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; +import { threat_subtechniques } from '../threat_subtechnique'; + +export const threat_technique_id = t.string; +export const threat_technique_name = t.string; +export const threat_technique_reference = t.string; + +export const threat_technique = t.intersection([ + t.exact( + t.type({ + id: threat_technique_id, + name: threat_technique_name, + reference: threat_technique_reference, + }) + ), + t.exact( + t.partial({ + subtechnique: threat_subtechniques, + }) + ), +]); +export const threat_techniques = t.array(threat_technique); + +export type ThreatTechnique = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts new file mode 100644 index 0000000000000..b4be7a4a97ff7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/throttle/index.ts @@ -0,0 +1,16 @@ +/* + * 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 * as t from 'io-ts'; +import { TimeDuration } from '@kbn/securitysolution-io-ts-types'; + +export type RuleActionThrottle = t.TypeOf; +export const RuleActionThrottle = t.union([ + t.literal('no_actions'), + t.literal('rule'), + TimeDuration({ allowedUnits: ['s', 'm', 'h', 'd'] }), +]); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/type/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/type/index.ts new file mode 100644 index 0000000000000..92b71faf14fe8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/src/type/index.ts @@ -0,0 +1,23 @@ +/* + * 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 * as t from 'io-ts'; + +export const type = t.keyof({ + eql: null, + machine_learning: null, + query: null, + saved_query: null, + threshold: null, + threat_match: null, + new_terms: null, + esql: null, +}); +export type Type = t.TypeOf; + +export const typeOrUndefined = t.union([type, t.undefined]); +export type TypeOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/tsconfig.json new file mode 100644 index 0000000000000..9b61aea31d977 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "kbn_references": [ + "@kbn/securitysolution-io-ts-types", + "@kbn/securitysolution-io-ts-utils" + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-io-ts-list-types/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/README.md similarity index 100% rename from packages/kbn-securitysolution-io-ts-list-types/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/index.ts new file mode 100644 index 0000000000000..90db551881094 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './src/common'; +export * from './src/request'; +export * from './src/response'; +export * from './src/typescript_types'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/jest.config.js b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/jest.config.js new file mode 100644 index 0000000000000..1e8525371d27c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types'], +}; diff --git a/packages/kbn-securitysolution-io-ts-list-types/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-io-ts-list-types/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/package.json new file mode 100644 index 0000000000000..da6c209015847 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/securitysolution-io-ts-list-types", + "version": "1.0.0", + "description": "io ts utilities and types to be shared with plugins from the security solution project", + "license": "Elastic License 2.0", + "private": true, + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.mock.ts new file mode 100644 index 0000000000000..69ad828a480ed --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.mock.ts @@ -0,0 +1,18 @@ +/* + * 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 { Comment, CommentsArray } from '.'; +import { DATE_NOW, ID, USER } from '../../constants/index.mock'; + +export const getCommentsMock = (): Comment => ({ + comment: 'some old comment', + created_at: DATE_NOW, + created_by: USER, + id: ID, +}); + +export const getCommentsArrayMock = (): CommentsArray => [getCommentsMock(), getCommentsMock()]; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.test.ts new file mode 100644 index 0000000000000..32a230fcf586d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.test.ts @@ -0,0 +1,236 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getCommentsArrayMock, getCommentsMock } from './index.mock'; +import { + Comment, + comment, + CommentsArray, + commentsArray, + CommentsArrayOrUndefined, + commentsArrayOrUndefined, +} from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { DATE_NOW } from '../../constants/index.mock'; + +describe('Comment', () => { + describe('comment', () => { + test('it fails validation when "id" is undefined', () => { + const payload = { ...getCommentsMock(), id: undefined }; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it passes validation with a typical comment', () => { + const payload = getCommentsMock(); + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it passes validation with "updated_at" and "updated_by" fields included', () => { + const payload = getCommentsMock(); + payload.updated_at = DATE_NOW; + payload.updated_by = 'someone'; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it fails validation when undefined', () => { + const payload = undefined; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when "comment" is an empty string', () => { + const payload: Omit & { comment: string } = { + ...getCommentsMock(), + comment: '', + }; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "comment"']); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when "comment" is not a string', () => { + const payload: Omit & { comment: string[] } = { + ...getCommentsMock(), + comment: ['some value'], + }; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "["some value"]" supplied to "comment"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when "created_at" is not a string', () => { + const payload: Omit & { created_at: number } = { + ...getCommentsMock(), + created_at: 1, + }; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "created_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when "created_by" is not a string', () => { + const payload: Omit & { created_by: number } = { + ...getCommentsMock(), + created_by: 1, + }; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "created_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when "updated_at" is not a string', () => { + const payload: Omit & { updated_at: number } = { + ...getCommentsMock(), + updated_at: 1, + }; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "updated_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when "updated_by" is not a string', () => { + const payload: Omit & { updated_by: number } = { + ...getCommentsMock(), + updated_by: 1, + }; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "updated_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: Comment & { + extraKey?: string; + } = getCommentsMock(); + payload.extraKey = 'some value'; + const decoded = comment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getCommentsMock()); + }); + }); + + describe('commentsArray', () => { + test('it passes validation an array of Comment', () => { + const payload = getCommentsArrayMock(); + const decoded = commentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it passes validation when a Comment includes "updated_at" and "updated_by"', () => { + const commentsPayload = getCommentsMock(); + commentsPayload.updated_at = DATE_NOW; + commentsPayload.updated_by = 'someone'; + const payload = [{ ...commentsPayload }, ...getCommentsArrayMock()]; + const decoded = commentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it fails validation when undefined', () => { + const payload = undefined; + const decoded = commentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when array includes non Comment types', () => { + const payload = [1] as unknown as CommentsArray; + const decoded = commentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + }); + + describe('commentsArrayOrUndefined', () => { + test('it passes validation an array of Comment', () => { + const payload = getCommentsArrayMock(); + const decoded = commentsArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it passes validation when undefined', () => { + const payload = undefined; + const decoded = commentsArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it fails validation when array includes non Comment types', () => { + const payload = [1] as unknown as CommentsArrayOrUndefined; + const decoded = commentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.ts new file mode 100644 index 0000000000000..48bce8fabafe7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/comment/index.ts @@ -0,0 +1,38 @@ +/* + * 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 * as t from 'io-ts'; + +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; +import { created_at } from '../created_at'; +import { created_by } from '../created_by'; +import { id } from '../id'; +import { updated_at } from '../updated_at'; +import { updated_by } from '../updated_by'; + +export const comment = t.intersection([ + t.exact( + t.type({ + comment: NonEmptyString, + created_at, + created_by, + id, + }) + ), + t.exact( + t.partial({ + updated_at, + updated_by, + }) + ), +]); + +export const commentsArray = t.array(comment); +export type CommentsArray = t.TypeOf; +export type Comment = t.TypeOf; +export const commentsArrayOrUndefined = t.union([commentsArray, t.undefined]); +export type CommentsArrayOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.mock.ts new file mode 100644 index 0000000000000..67be8d1f15da4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CreateComment, CreateCommentsArray } from '.'; + +export const getCreateCommentsMock = (): CreateComment => ({ + comment: 'some comments', +}); + +export const getCreateCommentsArrayMock = (): CreateCommentsArray => [getCreateCommentsMock()]; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.test.ts new file mode 100644 index 0000000000000..15fab1c35a19c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.test.ts @@ -0,0 +1,133 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getCreateCommentsArrayMock, getCreateCommentsMock } from './index.mock'; +import { + CreateComment, + createComment, + CreateCommentsArray, + createCommentsArray, + CreateCommentsArrayOrUndefined, + createCommentsArrayOrUndefined, +} from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('CreateComment', () => { + describe('createComment', () => { + test('it passes validation with a default comment', () => { + const payload = getCreateCommentsMock(); + const decoded = createComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it fails validation when undefined', () => { + const payload = undefined; + const decoded = createComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "{| comment: NonEmptyString |}"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when "comment" is not a string', () => { + const payload: Omit & { comment: string[] } = { + ...getCreateCommentsMock(), + comment: ['some value'], + }; + const decoded = createComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "["some value"]" supplied to "comment"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: CreateComment & { + extraKey?: string; + } = getCreateCommentsMock(); + payload.extraKey = 'some value'; + const decoded = createComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getCreateCommentsMock()); + }); + }); + + describe('createCommentsArray', () => { + test('it passes validation an array of comments', () => { + const payload = getCreateCommentsArrayMock(); + const decoded = createCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it fails validation when undefined', () => { + const payload = undefined; + const decoded = createCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "Array<{| comment: NonEmptyString |}>"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when array includes non comments types', () => { + const payload = [1] as unknown as CreateCommentsArray; + const decoded = createCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<{| comment: NonEmptyString |}>"', + ]); + expect(message.schema).toEqual({}); + }); + }); + + describe('createCommentsArrayOrUndefined', () => { + test('it passes validation an array of comments', () => { + const payload = getCreateCommentsArrayMock(); + const decoded = createCommentsArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it passes validation when undefined', () => { + const payload = undefined; + const decoded = createCommentsArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it fails validation when array includes non comments types', () => { + const payload = [1] as unknown as CreateCommentsArrayOrUndefined; + const decoded = createCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<{| comment: NonEmptyString |}>"', + ]); + expect(message.schema).toEqual({}); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.ts new file mode 100644 index 0000000000000..e0942203bac66 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/create_comment/index.ts @@ -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 * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +export const createComment = t.exact( + t.type({ + comment: NonEmptyString, + }) +); + +export type CreateComment = t.TypeOf; +export const createCommentsArray = t.array(createComment); +export type CreateCommentsArray = t.TypeOf; +export type CreateComments = t.TypeOf; +export const createCommentsArrayOrUndefined = t.union([createCommentsArray, t.undefined]); +export type CreateCommentsArrayOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/created_at/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/created_at/index.ts new file mode 100644 index 0000000000000..e962946e447e8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/created_at/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const created_at = t.string; // TODO: Make this into an ISO Date string check diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/created_by/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/created_by/index.ts new file mode 100644 index 0000000000000..ccf8d816f8e82 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/created_by/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const created_by = t.string; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/cursor/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/cursor/index.ts new file mode 100644 index 0000000000000..626b510ec8958 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/cursor/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const cursor = t.string; +export type Cursor = t.TypeOf; +export const cursorOrUndefined = t.union([cursor, t.undefined]); +export type CursorOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.test.ts new file mode 100644 index 0000000000000..af9f342c15e55 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.test.ts @@ -0,0 +1,64 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { CommentsArray } from '../comment'; +import { DefaultCommentsArray } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getCommentsArrayMock } from '../comment/index.mock'; + +describe('default_comments_array', () => { + test('it should pass validation when supplied an empty array', () => { + const payload: CommentsArray = []; + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should pass validation when supplied an array of comments', () => { + const payload: CommentsArray = getCommentsArrayMock(); + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when supplied an array of numbers', () => { + const payload = [1]; + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an array of strings', () => { + const payload = ['some string']; + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "some string" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default array entry', () => { + const payload = null; + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([]); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.ts new file mode 100644 index 0000000000000..af1576237b9ca --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_comments_array/index.ts @@ -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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { comment, CommentsArray } from '../comment'; + +/** + * Types the DefaultCommentsArray as: + * - If null or undefined, then a default array of type entry will be set + */ +export const DefaultCommentsArray = new t.Type( + 'DefaultCommentsArray', + t.array(comment).is, + (input): Either => + input == null ? t.success([]) : t.array(comment).decode(input), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.test.ts new file mode 100644 index 0000000000000..9f4aba07c9bf1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.test.ts @@ -0,0 +1,64 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { CommentsArray } from '../comment'; +import { DefaultCommentsArray } from '../default_comments_array'; +import { getCommentsArrayMock } from '../comment/index.mock'; + +describe('default_comments_array', () => { + test('it should pass validation when supplied an empty array', () => { + const payload: CommentsArray = []; + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should pass validation when supplied an array of comments', () => { + const payload: CommentsArray = getCommentsArrayMock(); + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when supplied an array of numbers', () => { + const payload = [1]; + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an array of strings', () => { + const payload = ['some string']; + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "some string" supplied to "Array<({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default array entry', () => { + const payload = null; + const decoded = DefaultCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([]); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.ts new file mode 100644 index 0000000000000..5b825578191f9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_create_comments_array/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { createComment, CreateCommentsArray } from '../create_comment'; + +/** + * Types the DefaultCreateComments as: + * - If null or undefined, then a default array of type entry will be set + */ +export const DefaultCreateCommentsArray = new t.Type< + CreateCommentsArray, + CreateCommentsArray, + unknown +>( + 'DefaultCreateComments', + t.array(createComment).is, + (input): Either => + input == null ? t.success([]) : t.array(createComment).decode(input), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.test.ts new file mode 100644 index 0000000000000..ea59988dfe0c5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.test.ts @@ -0,0 +1,86 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { ImportCommentsArray } from '../import_comment'; +import { DefaultImportCommentsArray } from '.'; +import { getCommentsArrayMock } from '../comment/index.mock'; +import { getCreateCommentsArrayMock } from '../create_comment/index.mock'; + +describe('default_import_comments_array', () => { + test('it should pass validation when supplied an empty array', () => { + const payload: ImportCommentsArray = []; + const decoded = DefaultImportCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should pass validation when supplied an array of comments', () => { + const payload: ImportCommentsArray = getCommentsArrayMock(); + const decoded = DefaultImportCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should pass validation when supplied an array of new comments', () => { + const payload: ImportCommentsArray = getCreateCommentsArrayMock(); + const decoded = DefaultImportCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should pass validation when supplied an array of new and existing comments', () => { + const payload: ImportCommentsArray = [ + ...getCommentsArrayMock(), + ...getCreateCommentsArrayMock(), + ]; + const decoded = DefaultImportCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when supplied an array of numbers', () => { + const payload = [1]; + const decoded = DefaultImportCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "DefaultImportComments"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an array of strings', () => { + const payload = ['some string']; + const decoded = DefaultImportCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "some string" supplied to "DefaultImportComments"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default array entry', () => { + const payload = null; + const decoded = DefaultImportCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([]); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.ts new file mode 100644 index 0000000000000..135288c2dd3f5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_import_comments_array/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { importComment, ImportCommentsArray } from '../import_comment'; + +/** + * Types the DefaultImportCommentsArray as: + * - If null or undefined, then a default array of type ImportCommentsArray will be set + */ +export const DefaultImportCommentsArray = new t.Type< + ImportCommentsArray, + ImportCommentsArray, + unknown +>( + 'DefaultImportComments', + t.array(importComment).is, + (input, context): Either => + input == null ? t.success([]) : t.array(importComment).validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.test.ts new file mode 100644 index 0000000000000..fc271855fc12e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.test.ts @@ -0,0 +1,60 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultNamespace } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_namespace', () => { + test('it should validate "single"', () => { + const payload = 'single'; + const decoded = DefaultNamespace.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate "agnostic"', () => { + const payload = 'agnostic'; + const decoded = DefaultNamespace.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it defaults to "single" if "undefined"', () => { + const payload = undefined; + const decoded = DefaultNamespace.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual('single'); + }); + + test('it defaults to "single" if "null"', () => { + const payload = null; + const decoded = DefaultNamespace.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual('single'); + }); + + test('it should FAIL validation if not "single" or "agnostic"', () => { + const payload = 'something else'; + const decoded = DefaultNamespace.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + `Invalid value "something else" supplied to "DefaultNamespace"`, + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.ts new file mode 100644 index 0000000000000..667ddbb82253d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; + +export const namespaceType = t.keyof({ agnostic: null, single: null }); +export type NamespaceType = t.TypeOf; + +/** + * Types the DefaultNamespace as: + * - If null or undefined, then a default string/enumeration of "single" will be used. + */ +export const DefaultNamespace = new t.Type( + 'DefaultNamespace', + namespaceType.is, + (input, context): Either => + input == null ? t.success('single') : namespaceType.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.test.ts new file mode 100644 index 0000000000000..cb7012503d382 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.test.ts @@ -0,0 +1,98 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultNamespaceArray, DefaultNamespaceArrayType } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('default_namespace_array', () => { + test('it should validate "null" single item as an array with a "single" value', () => { + const payload: DefaultNamespaceArrayType = null; + const decoded = DefaultNamespaceArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(['single']); + }); + + test('it should FAIL validation of numeric value', () => { + const payload = 5; + const decoded = DefaultNamespaceArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "5" supplied to "DefaultNamespaceArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should validate "undefined" item as an array with a "single" value', () => { + const payload: DefaultNamespaceArrayType = undefined; + const decoded = DefaultNamespaceArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(['single']); + }); + + test('it should validate "single" as an array of a "single" value', () => { + const payload: DefaultNamespaceArrayType = 'single'; + const decoded = DefaultNamespaceArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([payload]); + }); + + test('it should validate "agnostic" as an array of a "agnostic" value', () => { + const payload: DefaultNamespaceArrayType = 'agnostic'; + const decoded = DefaultNamespaceArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([payload]); + }); + + test('it should validate "single,agnostic" as an array of 2 values of ["single", "agnostic"] values', () => { + const payload: DefaultNamespaceArrayType = 'agnostic,single'; + const decoded = DefaultNamespaceArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(['agnostic', 'single']); + }); + + test('it should validate 3 elements of "single,agnostic,single" as an array of 3 values of ["single", "agnostic", "single"] values', () => { + const payload: DefaultNamespaceArrayType = 'single,agnostic,single'; + const decoded = DefaultNamespaceArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(['single', 'agnostic', 'single']); + }); + + test('it should validate 3 elements of "single,agnostic, single" as an array of 3 values of ["single", "agnostic", "single"] values when there are spaces', () => { + const payload: DefaultNamespaceArrayType = ' single, agnostic, single '; + const decoded = DefaultNamespaceArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(['single', 'agnostic', 'single']); + }); + + test('it should FAIL validation when given 3 elements of "single,agnostic,junk" since the 3rd value is junk', () => { + const payload: DefaultNamespaceArrayType = 'single,agnostic,junk'; + const decoded = DefaultNamespaceArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "junk" supplied to "DefaultNamespaceArray"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.ts new file mode 100644 index 0000000000000..494c6025f198e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_namespace_array/index.ts @@ -0,0 +1,43 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { namespaceType } from '../default_namespace'; + +export const namespaceTypeArray = t.array(namespaceType); +export type NamespaceTypeArray = t.TypeOf; + +/** + * Types the DefaultNamespaceArray as: + * - If null or undefined, then a default string array of "single" will be used. + * - If it contains a string, then it is split along the commas and puts them into an array and validates it + */ +export const DefaultNamespaceArray = new t.Type< + NamespaceTypeArray, + string | undefined | null, + unknown +>( + 'DefaultNamespaceArray', + namespaceTypeArray.is, + (input, context): Either => { + if (input == null) { + return t.success(['single']); + } else if (typeof input === 'string') { + const commaSeparatedValues = input + .trim() + .split(',') + .map((value) => value.trim()); + return namespaceTypeArray.validate(commaSeparatedValues, context); + } + return t.failure(input, context); + }, + String +); + +export type DefaultNamespaceArrayType = t.OutputOf; +export type DefaultNamespaceArrayTypeDecoded = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.test.ts new file mode 100644 index 0000000000000..3cced7284425c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.test.ts @@ -0,0 +1,64 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { UpdateCommentsArray } from '../update_comment'; +import { DefaultUpdateCommentsArray } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getUpdateCommentsArrayMock } from '../update_comment/index.mock'; + +describe('default_update_comments_array', () => { + test('it should pass validation when supplied an empty array', () => { + const payload: UpdateCommentsArray = []; + const decoded = DefaultUpdateCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should pass validation when supplied an array of comments', () => { + const payload: UpdateCommentsArray = getUpdateCommentsArrayMock(); + const decoded = DefaultUpdateCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when supplied an array of numbers', () => { + const payload = [1]; + const decoded = DefaultUpdateCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "DefaultUpdateComments"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an array of strings', () => { + const payload = ['some string']; + const decoded = DefaultUpdateCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "some string" supplied to "DefaultUpdateComments"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should return a default array entry', () => { + const payload = null; + const decoded = DefaultUpdateCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([]); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.ts new file mode 100644 index 0000000000000..28edd4af353e6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/default_update_comments_array/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { updateCommentsArray, UpdateCommentsArray } from '../update_comment'; + +/** + * Types the DefaultUpdateComments as: + * - If null or undefined, then a default array of type UpdateCommentsArray will be set + */ +export const DefaultUpdateCommentsArray = new t.Type< + UpdateCommentsArray, + UpdateCommentsArray, + unknown +>( + 'DefaultUpdateComments', + updateCommentsArray.is, + (input, context): Either => + input == null ? t.success([]) : updateCommentsArray.validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/description/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/description/index.ts new file mode 100644 index 0000000000000..adba3ae0ef4fa --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/description/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const description = t.string; +export type Description = t.TypeOf; +export const descriptionOrUndefined = t.union([description, t.undefined]); +export type DescriptionOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/deserializer/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/deserializer/index.ts new file mode 100644 index 0000000000000..4956736b5cf4e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/deserializer/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const deserializer = t.string; +export type Deserializer = t.TypeOf; +export const deserializerOrUndefined = t.union([deserializer, t.undefined]); +export type DeserializerOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts new file mode 100644 index 0000000000000..1d46d6412e122 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.mock.ts @@ -0,0 +1,19 @@ +/* + * 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 { EndpointEntriesArray } from '.'; +import { getEndpointEntryMatchMock } from '../entry_match/index.mock'; +import { getEndpointEntryMatchAnyMock } from '../entry_match_any/index.mock'; +import { getEndpointEntryNestedMock } from '../entry_nested/index.mock'; +import { getEndpointEntryMatchWildcardMock } from '../entry_match_wildcard/index.mock'; + +export const getEndpointEntriesArrayMock = (): EndpointEntriesArray => [ + getEndpointEntryMatchMock(), + getEndpointEntryMatchAnyMock(), + getEndpointEntryNestedMock(), + getEndpointEntryMatchWildcardMock(), +]; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts new file mode 100644 index 0000000000000..4a317d5c9152d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.test.ts @@ -0,0 +1,120 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEndpointEntryMatchMock } from '../entry_match/index.mock'; +import { + endpointEntriesArray, + nonEmptyEndpointEntriesArray, + NonEmptyEndpointEntriesArray, +} from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getEndpointEntryMatchAnyMock } from '../entry_match_any/index.mock'; +import { getEndpointEntryNestedMock } from '../entry_nested/index.mock'; +import { getEndpointEntriesArrayMock } from './index.mock'; +import { getEntryListMock } from '../../entries_list/index.mock'; +import { getEntryExistsMock } from '../../entries_exist/index.mock'; +import { getEndpointEntryMatchWildcardMock } from '../entry_match_wildcard/index.mock'; + +describe('Endpoint', () => { + describe('entriesArray', () => { + test('it should validate an array with match entry', () => { + const payload = [getEndpointEntryMatchMock()]; + const decoded = endpointEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array with match_any entry', () => { + const payload = [getEndpointEntryMatchAnyMock()]; + const decoded = endpointEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT validate an empty array', () => { + const payload: NonEmptyEndpointEntriesArray = []; + const decoded = nonEmptyEndpointEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "[]" supplied to "NonEmptyEndpointEntriesArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('type guard for nonEmptyEndpointNestedEntries should allow array of endpoint entries', () => { + const payload: NonEmptyEndpointEntriesArray = [getEndpointEntryMatchAnyMock()]; + const guarded = nonEmptyEndpointEntriesArray.is(payload); + expect(guarded).toBeTruthy(); + }); + + test('type guard for nonEmptyEndpointNestedEntries should disallow empty arrays', () => { + const payload: NonEmptyEndpointEntriesArray = []; + const guarded = nonEmptyEndpointEntriesArray.is(payload); + expect(guarded).toBeFalsy(); + }); + + test('it should NOT validate an array with exists entry', () => { + const payload = [getEntryExistsMock()]; + const decoded = endpointEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "exists" supplied to "type"', + 'Invalid value "undefined" supplied to "value"', + 'Invalid value "undefined" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT validate an array with list entry', () => { + const payload = [getEntryListMock()]; + const decoded = endpointEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "list" supplied to "type"', + 'Invalid value "undefined" supplied to "value"', + 'Invalid value "undefined" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should validate an array with nested entry', () => { + const payload = [getEndpointEntryNestedMock()]; + const decoded = endpointEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array with wildcard entry', () => { + const payload = [getEndpointEntryMatchWildcardMock()]; + const decoded = endpointEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array with all types of entries', () => { + const payload = getEndpointEntriesArrayMock(); + const decoded = endpointEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.ts new file mode 100644 index 0000000000000..c9a74ae525734 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entries/index.ts @@ -0,0 +1,48 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { endpointEntryMatch } from '../entry_match'; +import { endpointEntryMatchAny } from '../entry_match_any'; +import { endpointEntryNested } from '../entry_nested'; +import { endpointEntryMatchWildcard } from '../entry_match_wildcard'; + +export const endpointEntriesArray = t.array( + t.union([ + endpointEntryMatch, + endpointEntryMatchAny, + endpointEntryMatchWildcard, + endpointEntryNested, + ]) +); +export type EndpointEntriesArray = t.TypeOf; + +/** + * Types the nonEmptyEndpointEntriesArray as: + * - An array of entries of length 1 or greater + * + */ +export const nonEmptyEndpointEntriesArray = new t.Type< + EndpointEntriesArray, + EndpointEntriesArray, + unknown +>( + 'NonEmptyEndpointEntriesArray', + (u: unknown): u is EndpointEntriesArray => endpointEntriesArray.is(u) && u.length > 0, + (input, context): Either => { + if (Array.isArray(input) && input.length === 0) { + return t.failure(input, context); + } else { + return endpointEntriesArray.validate(input, context); + } + }, + t.identity +); + +export type NonEmptyEndpointEntriesArray = t.OutputOf; +export type NonEmptyEndpointEntriesArrayDecoded = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.mock.ts new file mode 100644 index 0000000000000..ddcda0e1e2d98 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { EndpointEntryMatch } from '.'; +import { ENTRY_VALUE, FIELD, MATCH, OPERATOR } from '../../../constants/index.mock'; + +export const getEndpointEntryMatchMock = (): EndpointEntryMatch => ({ + field: FIELD, + operator: OPERATOR, + type: MATCH, + value: ENTRY_VALUE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.test.ts new file mode 100644 index 0000000000000..561a36ab194c7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.test.ts @@ -0,0 +1,101 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEndpointEntryMatchMock } from './index.mock'; +import { EndpointEntryMatch, endpointEntryMatch } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getEntryMatchMock } from '../../entry_match/index.mock'; + +describe('endpointEntryMatch', () => { + test('it should validate an entry', () => { + const payload = getEndpointEntryMatchMock(); + const decoded = endpointEntryMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT validate when "operator" is "excluded"', () => { + // Use the generic entry mock so we can test operator: excluded + const payload = getEntryMatchMock(); + payload.operator = 'excluded'; + const decoded = endpointEntryMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "excluded" supplied to "operator"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "field" is empty string', () => { + const payload: Omit & { field: string } = { + ...getEndpointEntryMatchMock(), + field: '', + }; + const decoded = endpointEntryMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is not string', () => { + const payload: Omit & { value: string[] } = { + ...getEndpointEntryMatchMock(), + value: ['some value'], + }; + const decoded = endpointEntryMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "["some value"]" supplied to "value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is empty string', () => { + const payload: Omit & { value: string } = { + ...getEndpointEntryMatchMock(), + value: '', + }; + const decoded = endpointEntryMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "type" is not "match"', () => { + const payload: Omit & { type: string } = { + ...getEndpointEntryMatchMock(), + type: 'match_any', + }; + const decoded = endpointEntryMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "match_any" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EndpointEntryMatch & { + extraKey?: string; + } = getEndpointEntryMatchMock(); + payload.extraKey = 'some value'; + const decoded = endpointEntryMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryMatchMock()); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.ts new file mode 100644 index 0000000000000..7cc51636cf583 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match/index.ts @@ -0,0 +1,19 @@ +/* + * 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 * as t from 'io-ts'; +import { NonEmptyString, operatorIncluded } from '@kbn/securitysolution-io-ts-types'; + +export const endpointEntryMatch = t.exact( + t.type({ + field: NonEmptyString, + operator: operatorIncluded, + type: t.keyof({ match: null }), + value: NonEmptyString, + }) +); +export type EndpointEntryMatch = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.mock.ts new file mode 100644 index 0000000000000..6c04a6b596d63 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { ENTRY_VALUE, FIELD, MATCH_ANY, OPERATOR } from '../../../constants/index.mock'; +import { EndpointEntryMatchAny } from '.'; + +export const getEndpointEntryMatchAnyMock = (): EndpointEntryMatchAny => ({ + field: FIELD, + operator: OPERATOR, + type: MATCH_ANY, + value: [ENTRY_VALUE], +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.test.ts new file mode 100644 index 0000000000000..feb04606adf9c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.test.ts @@ -0,0 +1,99 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEndpointEntryMatchAnyMock } from './index.mock'; +import { EndpointEntryMatchAny, endpointEntryMatchAny } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getEntryMatchAnyMock } from '../../entry_match_any/index.mock'; + +describe('endpointEntryMatchAny', () => { + test('it should validate an entry', () => { + const payload = getEndpointEntryMatchAnyMock(); + const decoded = endpointEntryMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT validate when operator is "excluded"', () => { + // Use the generic entry mock so we can test operator: excluded + const payload = getEntryMatchAnyMock(); + payload.operator = 'excluded'; + const decoded = endpointEntryMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "excluded" supplied to "operator"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when field is empty string', () => { + const payload: Omit & { field: string } = { + ...getEndpointEntryMatchAnyMock(), + field: '', + }; + const decoded = endpointEntryMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when value is empty array', () => { + const payload: Omit & { value: string[] } = { + ...getEndpointEntryMatchAnyMock(), + value: [], + }; + const decoded = endpointEntryMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "[]" supplied to "value"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when value is not string array', () => { + const payload: Omit & { value: string } = { + ...getEndpointEntryMatchAnyMock(), + value: 'some string', + }; + const decoded = endpointEntryMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "some string" supplied to "value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "type" is not "match_any"', () => { + const payload: Omit & { type: string } = { + ...getEndpointEntryMatchAnyMock(), + type: 'match', + }; + const decoded = endpointEntryMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EndpointEntryMatchAny & { + extraKey?: string; + } = getEndpointEntryMatchAnyMock(); + payload.extraKey = 'some extra key'; + const decoded = endpointEntryMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryMatchAnyMock()); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.ts new file mode 100644 index 0000000000000..7d23e7338e71a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_any/index.ts @@ -0,0 +1,23 @@ +/* + * 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 * as t from 'io-ts'; +import { + NonEmptyString, + nonEmptyOrNullableStringArray, + operatorIncluded, +} from '@kbn/securitysolution-io-ts-types'; + +export const endpointEntryMatchAny = t.exact( + t.type({ + field: NonEmptyString, + operator: operatorIncluded, + type: t.keyof({ match_any: null }), + value: nonEmptyOrNullableStringArray, + }) +); +export type EndpointEntryMatchAny = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts new file mode 100644 index 0000000000000..ca8f01d3e30e0 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { ENTRY_VALUE, FIELD, OPERATOR, WILDCARD } from '../../../constants/index.mock'; +import { EndpointEntryMatchWildcard } from '.'; + +export const getEndpointEntryMatchWildcardMock = (): EndpointEntryMatchWildcard => ({ + field: FIELD, + operator: OPERATOR, + type: WILDCARD, + value: ENTRY_VALUE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.test.ts new file mode 100644 index 0000000000000..95ea73b2aac11 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.test.ts @@ -0,0 +1,96 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEndpointEntryMatchWildcardMock } from './index.mock'; +import { EndpointEntryMatchWildcard, endpointEntryMatchWildcard } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getEntryMatchWildcardMock } from '../../entry_match_wildcard/index.mock'; + +describe('endpointEntryMatchWildcard', () => { + test('it should validate an entry', () => { + const payload = getEndpointEntryMatchWildcardMock(); + const decoded = endpointEntryMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when "operator" is "excluded"', () => { + const payload = getEntryMatchWildcardMock(); + payload.operator = 'excluded'; + const decoded = endpointEntryMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when "field" is empty string', () => { + const payload: Omit & { field: string } = { + ...getEndpointEntryMatchWildcardMock(), + field: '', + }; + const decoded = endpointEntryMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is not string', () => { + const payload: Omit & { value: string[] } = { + ...getEndpointEntryMatchWildcardMock(), + value: ['some value'], + }; + const decoded = endpointEntryMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "["some value"]" supplied to "value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is empty string', () => { + const payload: Omit & { value: string } = { + ...getEndpointEntryMatchWildcardMock(), + value: '', + }; + const decoded = endpointEntryMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "type" is not "wildcard"', () => { + const payload: Omit & { type: string } = { + ...getEndpointEntryMatchWildcardMock(), + type: 'match', + }; + const decoded = endpointEntryMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EndpointEntryMatchWildcard & { + extraKey?: string; + } = getEndpointEntryMatchWildcardMock(); + payload.extraKey = 'some value'; + const decoded = endpointEntryMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryMatchWildcardMock()); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.ts new file mode 100644 index 0000000000000..cfc96337b6276 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_match_wildcard/index.ts @@ -0,0 +1,23 @@ +/* + * 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 * as t from 'io-ts'; +import { + NonEmptyString, + operatorExcluded, + operatorIncluded, +} from '@kbn/securitysolution-io-ts-types'; + +export const endpointEntryMatchWildcard = t.exact( + t.type({ + field: NonEmptyString, + operator: t.union([operatorIncluded, operatorExcluded]), + type: t.keyof({ wildcard: null }), + value: NonEmptyString, + }) +); +export type EndpointEntryMatchWildcard = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.mock.ts new file mode 100644 index 0000000000000..93b99e71b0bca --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.mock.ts @@ -0,0 +1,17 @@ +/* + * 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 { EndpointEntryNested } from '.'; +import { FIELD, NESTED } from '../../../constants/index.mock'; +import { getEndpointEntryMatchMock } from '../entry_match/index.mock'; +import { getEndpointEntryMatchAnyMock } from '../entry_match_any/index.mock'; + +export const getEndpointEntryNestedMock = (): EndpointEntryNested => ({ + entries: [getEndpointEntryMatchMock(), getEndpointEntryMatchAnyMock()], + field: FIELD, + type: NESTED, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.test.ts new file mode 100644 index 0000000000000..d68a0686a4391 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.test.ts @@ -0,0 +1,136 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { EndpointEntryNested, endpointEntryNested } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getEndpointEntryNestedMock } from './index.mock'; +import { getEndpointEntryMatchAnyMock } from '../entry_match_any/index.mock'; +import { + nonEmptyEndpointNestedEntriesArray, + NonEmptyEndpointNestedEntriesArray, +} from '../non_empty_nested_entries_array'; +import { getEndpointEntryMatchMock } from '../entry_match/index.mock'; +import { getEntryExistsMock } from '../../entries_exist/index.mock'; + +describe('endpointEntryNested', () => { + test('it should validate a nested entry', () => { + const payload = getEndpointEntryNestedMock(); + const decoded = endpointEntryNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when "type" is not "nested"', () => { + const payload: Omit & { type: 'match' } = { + ...getEndpointEntryNestedMock(), + type: 'match', + }; + const decoded = endpointEntryNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "field" is empty string', () => { + const payload: Omit & { + field: string; + } = { ...getEndpointEntryNestedMock(), field: '' }; + const decoded = endpointEntryNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "field" is not a string', () => { + const payload: Omit & { + field: number; + } = { ...getEndpointEntryNestedMock(), field: 1 }; + const decoded = endpointEntryNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "entries" is not an array', () => { + const payload: Omit & { + entries: string; + } = { ...getEndpointEntryNestedMock(), entries: 'im a string' }; + const decoded = endpointEntryNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "im a string" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should validate when "entries" contains an entry item that is type "match"', () => { + const payload = { ...getEndpointEntryNestedMock(), entries: [getEndpointEntryMatchAnyMock()] }; + const decoded = endpointEntryNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual({ + entries: [ + { + field: 'host.name', + operator: 'included', + type: 'match_any', + value: ['some host name'], + }, + ], + field: 'host.name', + type: 'nested', + }); + }); + + test('it should NOT validate when "entries" contains an entry item that is type "exists"', () => { + const payload = { ...getEndpointEntryNestedMock(), entries: [getEntryExistsMock()] }; + const decoded = endpointEntryNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "exists" supplied to "entries,type"', + 'Invalid value "undefined" supplied to "entries,value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EndpointEntryNested & { + extraKey?: string; + } = getEndpointEntryNestedMock(); + payload.extraKey = 'some extra key'; + const decoded = endpointEntryNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEndpointEntryNestedMock()); + }); + + test('type guard for nonEmptyEndpointNestedEntries should allow array of endpoint entries', () => { + const payload: NonEmptyEndpointNestedEntriesArray = [ + getEndpointEntryMatchMock(), + getEndpointEntryMatchAnyMock(), + ]; + const guarded = nonEmptyEndpointNestedEntriesArray.is(payload); + expect(guarded).toBeTruthy(); + }); + + test('type guard for nonEmptyEndpointNestedEntries should disallow empty arrays', () => { + const payload: NonEmptyEndpointNestedEntriesArray = []; + const guarded = nonEmptyEndpointNestedEntriesArray.is(payload); + expect(guarded).toBeFalsy(); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.ts new file mode 100644 index 0000000000000..f02570af1013e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/entry_nested/index.ts @@ -0,0 +1,19 @@ +/* + * 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 * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; +import { nonEmptyEndpointNestedEntriesArray } from '../non_empty_nested_entries_array'; + +export const endpointEntryNested = t.exact( + t.type({ + entries: nonEmptyEndpointNestedEntriesArray, + field: NonEmptyString, + type: t.keyof({ nested: null }), + }) +); +export type EndpointEntryNested = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/index.ts new file mode 100644 index 0000000000000..5138682f463b2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export * from './entries'; +export * from './non_empty_nested_entries_array'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/non_empty_nested_entries_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/non_empty_nested_entries_array/index.ts new file mode 100644 index 0000000000000..5085b4fdacac7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/endpoint/non_empty_nested_entries_array/index.ts @@ -0,0 +1,45 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { endpointEntryMatch } from '../entry_match'; +import { endpointEntryMatchAny } from '../entry_match_any'; + +export const endpointNestedEntriesArray = t.array( + t.union([endpointEntryMatch, endpointEntryMatchAny]) +); +export type EndpointNestedEntriesArray = t.TypeOf; + +/** + * Types the nonEmptyNestedEntriesArray as: + * - An array of entries of length 1 or greater + * + */ +export const nonEmptyEndpointNestedEntriesArray = new t.Type< + EndpointNestedEntriesArray, + EndpointNestedEntriesArray, + unknown +>( + 'NonEmptyEndpointNestedEntriesArray', + (u: unknown): u is EndpointNestedEntriesArray => endpointNestedEntriesArray.is(u) && u.length > 0, + (input, context): Either => { + if (Array.isArray(input) && input.length === 0) { + return t.failure(input, context); + } else { + return endpointNestedEntriesArray.validate(input, context); + } + }, + t.identity +); + +export type NonEmptyEndpointNestedEntriesArray = t.OutputOf< + typeof nonEmptyEndpointNestedEntriesArray +>; +export type NonEmptyEndpointNestedEntriesArrayDecoded = t.TypeOf< + typeof nonEmptyEndpointNestedEntriesArray +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.mock.ts new file mode 100644 index 0000000000000..1aeea284751b6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.mock.ts @@ -0,0 +1,30 @@ +/* + * 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 { EntriesArray } from '.'; +import { getEntryExistsMock } from '../entries_exist/index.mock'; +import { getEntryListMock } from '../entries_list/index.mock'; +import { getEntryMatchMock } from '../entry_match/index.mock'; +import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; +import { getEntryNestedMock } from '../entry_nested/index.mock'; + +export const getListAndNonListEntriesArrayMock = (): EntriesArray => [ + getEntryMatchMock(), + getEntryMatchAnyMock(), + getEntryListMock(), + getEntryExistsMock(), + getEntryNestedMock(), +]; + +export const getListEntriesArrayMock = (): EntriesArray => [getEntryListMock(), getEntryListMock()]; + +export const getEntriesArrayMock = (): EntriesArray => [ + getEntryMatchMock(), + getEntryMatchAnyMock(), + getEntryExistsMock(), + getEntryNestedMock(), +]; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.test.ts new file mode 100644 index 0000000000000..25c52b68a6f9d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.test.ts @@ -0,0 +1,147 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEntryMatchMock } from '../entry_match/index.mock'; +import { entriesArray, entriesArrayOrUndefined, entry } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; +import { getEntryExistsMock } from '../entries_exist/index.mock'; +import { getEntryListMock } from '../entries_list/index.mock'; +import { getEntryNestedMock } from '../entry_nested/index.mock'; +import { getEntriesArrayMock } from './index.mock'; + +describe('Entries', () => { + describe('entry', () => { + test('it should validate a match entry', () => { + const payload = getEntryMatchMock(); + const decoded = entry.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate a match_any entry', () => { + const payload = getEntryMatchAnyMock(); + const decoded = entry.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate a exists entry', () => { + const payload = getEntryExistsMock(); + const decoded = entry.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate a list entry', () => { + const payload = getEntryListMock(); + const decoded = entry.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation of nested entry', () => { + const payload = getEntryNestedMock(); + const decoded = entry.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "operator"', + 'Invalid value "nested" supplied to "type"', + 'Invalid value "undefined" supplied to "value"', + 'Invalid value "undefined" supplied to "list"', + ]); + expect(message.schema).toEqual({}); + }); + }); + + describe('entriesArray', () => { + test('it should validate an array with match entry', () => { + const payload = [getEntryMatchMock()]; + const decoded = entriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array with match_any entry', () => { + const payload = [getEntryMatchAnyMock()]; + const decoded = entriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array with exists entry', () => { + const payload = [getEntryExistsMock()]; + const decoded = entriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array with list entry', () => { + const payload = [getEntryListMock()]; + const decoded = entriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array with nested entry', () => { + const payload = [getEntryNestedMock()]; + const decoded = entriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array with all types of entries', () => { + const payload = [...getEntriesArrayMock()]; + const decoded = entriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + }); + + describe('entriesArrayOrUndefined', () => { + test('it should validate undefined', () => { + const payload = undefined; + const decoded = entriesArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array with nested entry', () => { + const payload = [getEntryNestedMock()]; + const decoded = entriesArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.ts new file mode 100644 index 0000000000000..73340d2c0af54 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries/index.ts @@ -0,0 +1,40 @@ +/* + * 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 * as t from 'io-ts'; +import { entriesExists } from '../entries_exist'; +import { entriesList } from '../entries_list'; +import { entriesMatch } from '../entry_match'; +import { entriesMatchAny } from '../entry_match_any'; +import { entriesMatchWildcard } from '../entry_match_wildcard'; +import { entriesNested } from '../entry_nested'; + +// NOTE: Type nested is not included here to denote it's non-recursive nature. +// So a nested entry is really just a collection of `Entry` types. +export const entry = t.union([ + entriesMatch, + entriesMatchAny, + entriesList, + entriesExists, + entriesMatchWildcard, +]); +export type Entry = t.TypeOf; + +export const entriesArray = t.array( + t.union([ + entriesMatch, + entriesMatchAny, + entriesList, + entriesExists, + entriesNested, + entriesMatchWildcard, + ]) +); +export type EntriesArray = t.TypeOf; + +export const entriesArrayOrUndefined = t.union([entriesArray, t.undefined]); +export type EntriesArrayOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.mock.ts new file mode 100644 index 0000000000000..e66d14c3c7af7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.mock.ts @@ -0,0 +1,20 @@ +/* + * 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 { EntryExists } from '.'; +import { EXISTS, FIELD, OPERATOR } from '../../constants/index.mock'; + +export const getEntryExistsMock = (): EntryExists => ({ + field: FIELD, + operator: OPERATOR, + type: EXISTS, +}); + +export const getEntryExistsExcludedMock = (): EntryExists => ({ + ...getEntryExistsMock(), + operator: 'excluded', +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.test.ts new file mode 100644 index 0000000000000..dcc6d47a437a1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.test.ts @@ -0,0 +1,78 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEntryExistsMock } from './index.mock'; +import { entriesExists, EntryExists } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('entriesExists', () => { + test('it should validate an entry', () => { + const payload = getEntryExistsMock(); + const decoded = entriesExists.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when "operator" is "included"', () => { + const payload = getEntryExistsMock(); + const decoded = entriesExists.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when "operator" is "excluded"', () => { + const payload = getEntryExistsMock(); + payload.operator = 'excluded'; + const decoded = entriesExists.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when "field" is empty string', () => { + const payload: Omit & { field: string } = { + ...getEntryExistsMock(), + field: '', + }; + const decoded = entriesExists.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EntryExists & { + extraKey?: string; + } = getEntryExistsMock(); + payload.extraKey = 'some extra key'; + const decoded = entriesExists.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryExistsMock()); + }); + + test('it should FAIL validation when "type" is not "exists"', () => { + const payload: Omit & { type: string } = { + ...getEntryExistsMock(), + type: 'match', + }; + const decoded = entriesExists.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.ts new file mode 100644 index 0000000000000..44c83c3f5b640 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_exist/index.ts @@ -0,0 +1,20 @@ +/* + * 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 * as t from 'io-ts'; + +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; +import { listOperator as operator } from '../list_operator'; + +export const entriesExists = t.exact( + t.type({ + field: NonEmptyString, + operator, + type: t.keyof({ exists: null }), + }) +); +export type EntryExists = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.mock.ts new file mode 100644 index 0000000000000..77c73d0bcfa38 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { EntryList } from '.'; +import { FIELD, LIST, LIST_ID, OPERATOR, TYPE } from '../../constants/index.mock'; + +export const getEntryListMock = (): EntryList => ({ + field: FIELD, + list: { id: LIST_ID, type: TYPE }, + operator: OPERATOR, + type: LIST, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.test.ts new file mode 100644 index 0000000000000..a9b56207d9590 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.test.ts @@ -0,0 +1,95 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEntryListMock } from './index.mock'; +import { entriesList, EntryList } from '.'; + +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('entriesList', () => { + test('it should validate an entry', () => { + const payload = getEntryListMock(); + const decoded = entriesList.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when operator is "included"', () => { + const payload = getEntryListMock(); + const decoded = entriesList.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when "operator" is "excluded"', () => { + const payload = getEntryListMock(); + payload.operator = 'excluded'; + const decoded = entriesList.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when "list" is not expected value', () => { + const payload: Omit & { list: string } = { + ...getEntryListMock(), + list: 'someListId', + }; + const decoded = entriesList.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "someListId" supplied to "list"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "list.id" is empty string', () => { + const payload: Omit & { list: { id: string; type: 'ip' } } = { + ...getEntryListMock(), + list: { id: '', type: 'ip' }, + }; + const decoded = entriesList.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "list,id"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "type" is not "lists"', () => { + const payload: Omit & { type: 'match_any' } = { + ...getEntryListMock(), + type: 'match_any', + }; + const decoded = entriesList.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "match_any" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EntryList & { + extraKey?: string; + } = getEntryListMock(); + payload.extraKey = 'some extra key'; + const decoded = entriesList.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryListMock()); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.ts new file mode 100644 index 0000000000000..214f0c92db221 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entries_list/index.ts @@ -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 * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +import { type } from '../type'; +import { listOperator as operator } from '../list_operator'; + +export const entriesList = t.exact( + t.type({ + field: NonEmptyString, + list: t.exact(t.type({ id: NonEmptyString, type })), + operator, + type: t.keyof({ list: null }), + }) +); +export type EntryList = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.mock.ts new file mode 100644 index 0000000000000..9af6cf08090b9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.mock.ts @@ -0,0 +1,21 @@ +/* + * 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 { EntryMatch } from '.'; +import { ENTRY_VALUE, FIELD, MATCH, OPERATOR } from '../../constants/index.mock'; + +export const getEntryMatchMock = (): EntryMatch => ({ + field: FIELD, + operator: OPERATOR, + type: MATCH, + value: ENTRY_VALUE, +}); + +export const getEntryMatchExcludeMock = (): EntryMatch => ({ + ...getEntryMatchMock(), + operator: 'excluded', +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.test.ts new file mode 100644 index 0000000000000..6f2fc7fd9e8d6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.test.ts @@ -0,0 +1,106 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEntryMatchMock } from './index.mock'; +import { entriesMatch, EntryMatch } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('entriesMatch', () => { + test('it should validate an entry', () => { + const payload = getEntryMatchMock(); + const decoded = entriesMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when operator is "included"', () => { + const payload = getEntryMatchMock(); + const decoded = entriesMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when "operator" is "excluded"', () => { + const payload = getEntryMatchMock(); + payload.operator = 'excluded'; + const decoded = entriesMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when "field" is empty string', () => { + const payload: Omit & { field: string } = { + ...getEntryMatchMock(), + field: '', + }; + const decoded = entriesMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is not string', () => { + const payload: Omit & { value: string[] } = { + ...getEntryMatchMock(), + value: ['some value'], + }; + const decoded = entriesMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "["some value"]" supplied to "value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is empty string', () => { + const payload: Omit & { value: string } = { + ...getEntryMatchMock(), + value: '', + }; + const decoded = entriesMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "type" is not "match"', () => { + const payload: Omit & { type: string } = { + ...getEntryMatchMock(), + type: 'match_any', + }; + const decoded = entriesMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "match_any" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EntryMatch & { + extraKey?: string; + } = getEntryMatchMock(); + payload.extraKey = 'some value'; + const decoded = entriesMatch.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryMatchMock()); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.ts new file mode 100644 index 0000000000000..8e56991b977a7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match/index.ts @@ -0,0 +1,20 @@ +/* + * 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 * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; +import { listOperator as operator } from '../list_operator'; + +export const entriesMatch = t.exact( + t.type({ + field: NonEmptyString, + operator, + type: t.keyof({ match: null }), + value: NonEmptyString, + }) +); +export type EntryMatch = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.mock.ts new file mode 100644 index 0000000000000..a564d4e8fd95b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.mock.ts @@ -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 { EntryMatchAny } from '.'; +import { ENTRY_VALUE, FIELD, MATCH_ANY, OPERATOR } from '../../constants/index.mock'; + +export const getEntryMatchAnyMock = (): EntryMatchAny => ({ + field: FIELD, + operator: OPERATOR, + type: MATCH_ANY, + value: [ENTRY_VALUE], +}); + +export const getEntryMatchAnyExcludeMock = (): EntryMatchAny => ({ + ...getEntryMatchAnyMock(), + operator: 'excluded', + value: [ENTRY_VALUE, 'some other host name'], +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.test.ts new file mode 100644 index 0000000000000..84844c432aa2c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.test.ts @@ -0,0 +1,104 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEntryMatchAnyMock } from './index.mock'; +import { entriesMatchAny, EntryMatchAny } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('entriesMatchAny', () => { + test('it should validate an entry', () => { + const payload = getEntryMatchAnyMock(); + const decoded = entriesMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when operator is "included"', () => { + const payload = getEntryMatchAnyMock(); + const decoded = entriesMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when operator is "excluded"', () => { + const payload = getEntryMatchAnyMock(); + payload.operator = 'excluded'; + const decoded = entriesMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when field is empty string', () => { + const payload: Omit & { field: string } = { + ...getEntryMatchAnyMock(), + field: '', + }; + const decoded = entriesMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when value is empty array', () => { + const payload: Omit & { value: string[] } = { + ...getEntryMatchAnyMock(), + value: [], + }; + const decoded = entriesMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "[]" supplied to "value"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when value is not string array', () => { + const payload: Omit & { value: string } = { + ...getEntryMatchAnyMock(), + value: 'some string', + }; + const decoded = entriesMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "some string" supplied to "value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "type" is not "match_any"', () => { + const payload: Omit & { type: string } = { + ...getEntryMatchAnyMock(), + type: 'match', + }; + const decoded = entriesMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EntryMatchAny & { + extraKey?: string; + } = getEntryMatchAnyMock(); + payload.extraKey = 'some extra key'; + const decoded = entriesMatchAny.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryMatchAnyMock()); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.ts new file mode 100644 index 0000000000000..989c729f8b1b1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_any/index.ts @@ -0,0 +1,21 @@ +/* + * 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 * as t from 'io-ts'; + +import { NonEmptyString, nonEmptyOrNullableStringArray } from '@kbn/securitysolution-io-ts-types'; +import { listOperator as operator } from '../list_operator'; + +export const entriesMatchAny = t.exact( + t.type({ + field: NonEmptyString, + operator, + type: t.keyof({ match_any: null }), + value: nonEmptyOrNullableStringArray, + }) +); +export type EntryMatchAny = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.mock.ts new file mode 100644 index 0000000000000..c279fe3ed45dd --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.mock.ts @@ -0,0 +1,21 @@ +/* + * 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 { EntryMatchWildcard } from '.'; +import { ENTRY_VALUE, FIELD, OPERATOR, WILDCARD } from '../../constants/index.mock'; + +export const getEntryMatchWildcardMock = (): EntryMatchWildcard => ({ + field: FIELD, + operator: OPERATOR, + type: WILDCARD, + value: ENTRY_VALUE, +}); + +export const getEntryMatchWildcardExcludeMock = (): EntryMatchWildcard => ({ + ...getEntryMatchWildcardMock(), + operator: 'excluded', +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.test.ts new file mode 100644 index 0000000000000..4bd2d146412a8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.test.ts @@ -0,0 +1,104 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEntryMatchWildcardMock } from './index.mock'; +import { entriesMatchWildcard, EntryMatchWildcard } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('entriesMatchWildcard', () => { + test('it should validate an entry', () => { + const payload = getEntryMatchWildcardMock(); + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when operator is "included"', () => { + const payload = getEntryMatchWildcardMock(); + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when "operator" is "excluded"', () => { + const payload = getEntryMatchWildcardMock(); + payload.operator = 'excluded'; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when "field" is empty string', () => { + const payload: Omit & { field: string } = { + ...getEntryMatchWildcardMock(), + field: '', + }; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is not string', () => { + const payload: Omit & { value: string[] } = { + ...getEntryMatchWildcardMock(), + value: ['some value'], + }; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "["some value"]" supplied to "value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "value" is empty string', () => { + const payload: Omit & { value: string } = { + ...getEntryMatchWildcardMock(), + value: '', + }; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "value"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "type" is not "wildcard"', () => { + const payload: Omit & { type: string } = { + ...getEntryMatchWildcardMock(), + type: 'match', + }; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: EntryMatchWildcard & { + extraKey?: string; + } = getEntryMatchWildcardMock(); + payload.extraKey = 'some value'; + const decoded = entriesMatchWildcard.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryMatchWildcardMock()); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.ts new file mode 100644 index 0000000000000..af168e33fa70a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_match_wildcard/index.ts @@ -0,0 +1,20 @@ +/* + * 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 * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; +import { listOperator as operator } from '../list_operator'; + +export const entriesMatchWildcard = t.exact( + t.type({ + field: NonEmptyString, + operator, + type: t.keyof({ wildcard: null }), + value: NonEmptyString, + }) +); +export type EntryMatchWildcard = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.mock.ts new file mode 100644 index 0000000000000..890c3d379d27d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.mock.ts @@ -0,0 +1,28 @@ +/* + * 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 { EntryNested } from '.'; +import { NESTED, NESTED_FIELD } from '../../constants/index.mock'; +import { getEntryExistsMock } from '../entries_exist/index.mock'; +import { getEntryMatchExcludeMock, getEntryMatchMock } from '../entry_match/index.mock'; +import { getEntryMatchAnyExcludeMock, getEntryMatchAnyMock } from '../entry_match_any/index.mock'; + +export const getEntryNestedMock = (): EntryNested => ({ + entries: [getEntryMatchMock(), getEntryMatchAnyMock()], + field: NESTED_FIELD, + type: NESTED, +}); + +export const getEntryNestedExcludeMock = (): EntryNested => ({ + ...getEntryNestedMock(), + entries: [getEntryMatchExcludeMock(), getEntryMatchAnyExcludeMock()], +}); + +export const getEntryNestedMixedEntries = (): EntryNested => ({ + ...getEntryNestedMock(), + entries: [getEntryMatchMock(), getEntryMatchAnyExcludeMock(), getEntryExistsMock()], +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.test.ts new file mode 100644 index 0000000000000..be37a0273bce9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.test.ts @@ -0,0 +1,123 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEntryNestedMock } from './index.mock'; +import { entriesNested, EntryNested } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; +import { getEntryExistsMock } from '../entries_exist/index.mock'; + +describe('entriesNested', () => { + test('it should validate a nested entry', () => { + const payload = getEntryNestedMock(); + const decoded = entriesNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when "type" is not "nested"', () => { + const payload: Omit & { type: 'match' } = { + ...getEntryNestedMock(), + type: 'match', + }; + const decoded = entriesNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "match" supplied to "type"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "field" is empty string', () => { + const payload: Omit & { + field: string; + } = { ...getEntryNestedMock(), field: '' }; + const decoded = entriesNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "field" is not a string', () => { + const payload: Omit & { + field: number; + } = { ...getEntryNestedMock(), field: 1 }; + const decoded = entriesNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "field"']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when "entries" is not a an array', () => { + const payload: Omit & { + entries: string; + } = { ...getEntryNestedMock(), entries: 'im a string' }; + const decoded = entriesNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "im a string" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should validate when "entries" contains an entry item that is type "match"', () => { + const payload = { ...getEntryNestedMock(), entries: [getEntryMatchAnyMock()] }; + const decoded = entriesNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual({ + entries: [ + { + field: 'host.name', + operator: 'included', + type: 'match_any', + value: ['some host name'], + }, + ], + field: 'parent.field', + type: 'nested', + }); + }); + + test('it should validate when "entries" contains an entry item that is type "exists"', () => { + const payload = { ...getEntryNestedMock(), entries: [getEntryExistsMock()] }; + const decoded = entriesNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual({ + entries: [ + { + field: 'host.name', + operator: 'included', + type: 'exists', + }, + ], + field: 'parent.field', + type: 'nested', + }); + }); + + test('it should strip out extra keys', () => { + const payload: EntryNested & { + extraKey?: string; + } = getEntryNestedMock(); + payload.extraKey = 'some extra key'; + const decoded = entriesNested.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getEntryNestedMock()); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.ts new file mode 100644 index 0000000000000..dac5d6a3d5a88 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/entry_nested/index.ts @@ -0,0 +1,19 @@ +/* + * 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 * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; +import { nonEmptyNestedEntriesArray } from '../non_empty_nested_entries_array'; + +export const entriesNested = t.exact( + t.type({ + entries: nonEmptyNestedEntriesArray, + field: NonEmptyString, + type: t.keyof({ nested: null }), + }) +); +export type EntryNested = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.mock.ts new file mode 100644 index 0000000000000..ded6a6bfbb8ab --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.mock.ts @@ -0,0 +1,28 @@ +/* + * 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 { ExportExceptionDetails } from '.'; + +export interface ExportExceptionDetailsMock { + listCount?: number; + missingListsCount?: number; + missingLists?: Array>; + itemCount?: number; + missingItemCount?: number; + missingItems?: Array>; +} + +export const getExceptionExportDetailsMock = ( + details?: ExportExceptionDetailsMock +): ExportExceptionDetails => ({ + exported_exception_list_count: details?.listCount ?? 0, + exported_exception_list_item_count: details?.itemCount ?? 0, + missing_exception_list_item_count: details?.missingItemCount ?? 0, + missing_exception_list_items: details?.missingItems ?? [], + missing_exception_lists: details?.missingLists ?? [], + missing_exception_lists_count: details?.missingListsCount ?? 0, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.test.ts new file mode 100644 index 0000000000000..fe8150fd6f3be --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.test.ts @@ -0,0 +1,35 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getExceptionExportDetailsMock } from './index.mock'; +import { exportExceptionDetailsSchema, ExportExceptionDetails } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('exportExceptionDetails', () => { + test('it should validate export meta', () => { + const payload = getExceptionExportDetailsMock(); + const decoded = exportExceptionDetailsSchema.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should strip out extra keys', () => { + const payload: ExportExceptionDetails & { + extraKey?: string; + } = getExceptionExportDetailsMock(); + payload.extraKey = 'some extra key'; + const decoded = exportExceptionDetailsSchema.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getExceptionExportDetailsMock()); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.ts new file mode 100644 index 0000000000000..358e987d8b178 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_export_details/index.ts @@ -0,0 +1,34 @@ +/* + * 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 * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +export const exportExceptionDetails = { + exported_exception_list_count: t.number, + exported_exception_list_item_count: t.number, + missing_exception_list_item_count: t.number, + missing_exception_list_items: t.array( + t.exact( + t.type({ + item_id: NonEmptyString, + }) + ) + ), + missing_exception_lists: t.array( + t.exact( + t.type({ + list_id: NonEmptyString, + }) + ) + ), + missing_exception_lists_count: t.number, +}; + +export const exportExceptionDetailsSchema = t.exact(t.type(exportExceptionDetails)); + +export type ExportExceptionDetails = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.test.ts new file mode 100644 index 0000000000000..ac57828355d36 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.test.ts @@ -0,0 +1,53 @@ +/* + * 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 { exceptionListType, ExceptionListTypeEnum } from '.'; + +import { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('exceptionListType', () => { + test('it should validate for "detection"', () => { + const payload = 'detection'; + const decoded = exceptionListType.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate for "rule_default"', () => { + const payload = 'rule_default'; + const decoded = exceptionListType.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate for "endpoint"', () => { + const payload = 'endpoint'; + const decoded = exceptionListType.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should contain same amount of keys as enum', () => { + // Might seem like a weird test, but its meant to + // ensure that if exceptionListType is updated, you + // also update the ExceptionListTypeEnum, a workaround + // for io-ts not yet supporting enums + // https://github.com/gcanti/io-ts/issues/67 + const keys = Object.keys(exceptionListType.keys).sort().join(',').toLowerCase(); + const enumKeys = Object.keys(ExceptionListTypeEnum).sort().join(',').toLowerCase(); + + expect(keys).toEqual(enumKeys); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.ts new file mode 100644 index 0000000000000..50273a9c55a99 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list/index.ts @@ -0,0 +1,30 @@ +/* + * 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 * as t from 'io-ts'; + +export const exceptionListType = t.keyof({ + detection: null, + rule_default: null, + endpoint: null, + endpoint_trusted_apps: null, + endpoint_events: null, + endpoint_host_isolation_exceptions: null, + endpoint_blocklists: null, +}); +export const exceptionListTypeOrUndefined = t.union([exceptionListType, t.undefined]); +export type ExceptionListType = t.TypeOf; +export type ExceptionListTypeOrUndefined = t.TypeOf; +export enum ExceptionListTypeEnum { + DETECTION = 'detection', // shared exception list type + RULE_DEFAULT = 'rule_default', // rule default, cannot be shared + ENDPOINT = 'endpoint', + ENDPOINT_TRUSTED_APPS = 'endpoint', + ENDPOINT_EVENTS = 'endpoint_events', + ENDPOINT_HOST_ISOLATION_EXCEPTIONS = 'endpoint_host_isolation_exceptions', + ENDPOINT_BLOCKLISTS = 'endpoint_blocklists', +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list_item_type/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list_item_type/index.ts new file mode 100644 index 0000000000000..36857aec92dfd --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/exception_list_item_type/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const exceptionListItemType = t.keyof({ simple: null }); +export const exceptionListItemTypeOrUndefined = t.union([exceptionListItemType, t.undefined]); +export type ExceptionListItemType = t.TypeOf; +export type ExceptionListItemTypeOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/expire_time/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/expire_time/index.ts new file mode 100644 index 0000000000000..9a3f4db110ed1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/expire_time/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; +import { IsoDateString } from '@kbn/securitysolution-io-ts-types'; + +export const expireTime = IsoDateString; +export const expireTimeOrUndefined = t.union([expireTime, t.undefined]); +export type ExpireTimeOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/file/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/file/index.ts new file mode 100644 index 0000000000000..885d714de4411 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/file/index.ts @@ -0,0 +1,10 @@ +/* + * 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 * as t from 'io-ts'; + +export const file = t.object; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/filter/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/filter/index.ts new file mode 100644 index 0000000000000..43ac9592ed31e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/filter/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const filter = t.string; +export type Filter = t.TypeOf; +export const filterOrUndefined = t.union([filter, t.undefined]); +export type FilterOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/id/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/id/index.ts new file mode 100644 index 0000000000000..967282c158a27 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/id/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +export const id = NonEmptyString; +export type Id = t.TypeOf; +export const idOrUndefined = t.union([id, t.undefined]); +export type IdOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/immutable/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/immutable/index.ts new file mode 100644 index 0000000000000..afeb2de36ea1d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/immutable/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const immutable = t.boolean; +export type Immutable = t.TypeOf; +export const immutableOrUndefined = t.union([immutable, t.undefined]); +export type ImmutableOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.test.ts new file mode 100644 index 0000000000000..a447d1f535071 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.test.ts @@ -0,0 +1,134 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getCommentsArrayMock, getCommentsMock } from '../comment/index.mock'; +import { getCreateCommentsArrayMock } from '../create_comment/index.mock'; +import { + importComment, + ImportCommentsArray, + importCommentsArray, + ImportCommentsArrayOrUndefined, + importCommentsArrayOrUndefined, +} from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('ImportComment', () => { + describe('importComment', () => { + test('it passes validation with a typical comment', () => { + const payload = getCommentsMock(); + const decoded = importComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it passes validation with a new comment', () => { + const payload = { comment: 'new comment' }; + const decoded = importComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it fails validation when undefined', () => { + const payload = undefined; + const decoded = importComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "(({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>) | {| comment: NonEmptyString |})"', + ]); + expect(message.schema).toEqual({}); + }); + }); + + describe('importCommentsArray', () => { + test('it passes validation an array of Comment', () => { + const payload = getCommentsArrayMock(); + const decoded = importCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it passes validation an array of CreateComment', () => { + const payload = getCreateCommentsArrayMock(); + const decoded = importCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it passes validation an array of Comment and CreateComment', () => { + const payload = [...getCommentsArrayMock(), ...getCreateCommentsArrayMock()]; + const decoded = importCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it fails validation when undefined', () => { + const payload = undefined; + const decoded = importCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "Array<(({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>) | {| comment: NonEmptyString |})>"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it fails validation when array includes non ImportComment types', () => { + const payload = [1] as unknown as ImportCommentsArray; + const decoded = importCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<(({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>) | {| comment: NonEmptyString |})>"', + ]); + expect(message.schema).toEqual({}); + }); + }); + + describe('importCommentsArrayOrUndefined', () => { + test('it passes validation an array of ImportComment', () => { + const payload = [...getCommentsArrayMock(), ...getCreateCommentsArrayMock()]; + const decoded = importCommentsArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it passes validation when undefined', () => { + const payload = undefined; + const decoded = importCommentsArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it fails validation when array includes non ImportComment types', () => { + const payload = [1] as unknown as ImportCommentsArrayOrUndefined; + const decoded = importCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<(({| comment: NonEmptyString, created_at: string, created_by: string, id: NonEmptyString |} & Partial<{| updated_at: string, updated_by: string |}>) | {| comment: NonEmptyString |})>"', + ]); + expect(message.schema).toEqual({}); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.ts new file mode 100644 index 0000000000000..c4c906117ecdb --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/import_comment/index.ts @@ -0,0 +1,18 @@ +/* + * 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 * as t from 'io-ts'; +import { createComment } from '../create_comment'; +import { comment } from '../comment'; + +export const importComment = t.union([comment, createComment]); + +export type ImportComment = t.TypeOf; +export const importCommentsArray = t.array(importComment); +export type ImportCommentsArray = t.TypeOf; +export const importCommentsArrayOrUndefined = t.union([importCommentsArray, t.undefined]); +export type ImportCommentsArrayOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/include_expired_exceptions/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/include_expired_exceptions/index.ts new file mode 100644 index 0000000000000..0c3d5e4959bc4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/include_expired_exceptions/index.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const include_expired_exceptions = t.keyof({ true: null, false: null }); +export const includeExpiredExceptionsOrUndefined = t.union([ + include_expired_exceptions, + t.undefined, +]); +export type IncludeExpiredExceptionsOrUndefined = t.TypeOf< + typeof includeExpiredExceptionsOrUndefined +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/index.ts new file mode 100644 index 0000000000000..0ff54c5e5a726 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/index.ts @@ -0,0 +1,65 @@ +/* + * 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. + */ + +export * from './comment'; +export * from './create_comment'; +export * from './created_at'; +export * from './created_by'; +export * from './cursor'; +export * from './default_namespace'; +export * from './default_namespace_array'; +export * from './default_create_comments_array'; +export * from './default_import_comments_array'; +export * from './description'; +export * from './deserializer'; +export * from './endpoint'; +export * from './entries'; +export * from './entries_exist'; +export * from './entries_list'; +export * from './entry_match'; +export * from './entry_match_any'; +export * from './entry_match_wildcard'; +export * from './entry_nested'; +export * from './exception_export_details'; +export * from './exception_list'; +export * from './exception_list_item_type'; +export * from './expire_time'; +export * from './filter'; +export * from './id'; +export * from './immutable'; +export * from './import_comment'; +export * from './item_id'; +export * from './list_id'; +export * from './list_operator'; +export * from './list_type'; +export * from './lists'; +export * from './lists_default_array'; +export * from './max_size'; +export * from './meta'; +export * from './name'; +export * from './namespace_type'; +export * from './non_empty_entries_array'; +export * from './non_empty_nested_entries_array'; +export * from './os_type'; +export * from './page'; +export * from './per_page'; +export * from './pit'; +export * from './search'; +export * from './search_after'; +export * from './serializer'; +export * from './sort_field'; +export * from './sort_order'; +export * from './tags'; +export * from './tie_breaker_id'; +export * from './timestamp'; +export * from './total'; +export * from './type'; +export * from './underscore_version'; +export * from './update_comment'; +export * from './updated_at'; +export * from './updated_by'; +export * from './refresh'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/item/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/item/index.ts new file mode 100644 index 0000000000000..5a71e1242d26e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/item/index.ts @@ -0,0 +1,10 @@ +/* + * 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 * as t from 'io-ts'; + +export const item = t.string; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/item_id/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/item_id/index.ts new file mode 100644 index 0000000000000..44ccc97d46664 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/item_id/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +export const item_id = NonEmptyString; +export type ItemId = t.TypeOf; +export const itemIdOrUndefined = t.union([item_id, t.undefined]); +export type ItemIdOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_id/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_id/index.ts new file mode 100644 index 0000000000000..c813d7170e8ad --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_id/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; + +export const list_id = NonEmptyString; +export type ListId = t.TypeOf; +export const list_idOrUndefined = t.union([list_id, t.undefined]); +export type ListIdOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.test.ts new file mode 100644 index 0000000000000..d3d67a8fd60a8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.test.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { ListOperatorEnum as OperatorEnum, listOperator as operator } from '.'; + +describe('operator', () => { + test('it should validate for "included"', () => { + const payload = 'included'; + const decoded = operator.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate for "excluded"', () => { + const payload = 'excluded'; + const decoded = operator.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should contain same amount of keys as enum', () => { + // Might seem like a weird test, but its meant to + // ensure that if operator is updated, you + // also update the operatorEnum, a workaround + // for io-ts not yet supporting enums + // https://github.com/gcanti/io-ts/issues/67 + const keys = Object.keys(operator.keys).sort().join(',').toLowerCase(); + const enumKeys = Object.keys(OperatorEnum).sort().join(',').toLowerCase(); + + expect(keys).toEqual(enumKeys); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.ts new file mode 100644 index 0000000000000..096b21ec20f90 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_operator/index.ts @@ -0,0 +1,33 @@ +/* + * 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 * as t from 'io-ts'; + +export const listOperator = t.keyof({ excluded: null, included: null }); +export type ListOperator = t.TypeOf; +export enum ListOperatorEnum { + INCLUDED = 'included', + EXCLUDED = 'excluded', +} + +export const listOperatorType = t.keyof({ + nested: null, + match: null, + match_any: null, + wildcard: null, + exists: null, + list: null, +}); +export type ListOperatorType = t.TypeOf; +export enum ListOperatorTypeEnum { + NESTED = 'nested', + MATCH = 'match', + MATCH_ANY = 'match_any', + WILDCARD = 'wildcard', + EXISTS = 'exists', + LIST = 'list', +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_type/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_type/index.ts new file mode 100644 index 0000000000000..7a160486c3994 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/list_type/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const list_type = t.keyof({ item: null, list: null }); +export type ListType = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts new file mode 100644 index 0000000000000..6ad3c6a371d18 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { List, ListArray } from '.'; +import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; + +export const getListMock = (): List => ({ + id: 'some_uuid', + list_id: 'list_id_single', + namespace_type: 'single', + type: 'detection', +}); + +export const getEndpointListMock = (): List => ({ + id: ENDPOINT_LIST_ID, + list_id: ENDPOINT_LIST_ID, + namespace_type: 'agnostic', + type: 'endpoint', +}); + +export const getListArrayMock = (): ListArray => [getListMock(), getEndpointListMock()]; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.test.ts new file mode 100644 index 0000000000000..aecfe9501ac17 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.test.ts @@ -0,0 +1,125 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getEndpointListMock, getListArrayMock, getListMock } from './index.mock'; +import { List, list, ListArray, listArray, ListArrayOrUndefined, listArrayOrUndefined } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('Lists', () => { + describe('list', () => { + test('it should validate a list', () => { + const payload = getListMock(); + const decoded = list.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate a list with "namespace_type" of "agnostic"', () => { + const payload = getEndpointListMock(); + const decoded = list.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT validate a list without an "id"', () => { + const payload = getListMock(); + // @ts-expect-error + delete payload.id; + const decoded = list.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT validate a list without "namespace_type"', () => { + const payload = getListMock(); + // @ts-expect-error + delete payload.namespace_type; + const decoded = list.decode(payload); + const message = pipe(decoded, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "namespace_type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra keys', () => { + const payload: List & { + extraKey?: string; + } = getListMock(); + payload.extraKey = 'some value'; + const decoded = list.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getListMock()); + }); + }); + + describe('listArray', () => { + test('it should validate an array of lists', () => { + const payload = getListArrayMock(); + const decoded = listArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate when unexpected type found in array', () => { + const payload = [1] as unknown as ListArray; + const decoded = listArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<{| id: NonEmptyString, list_id: NonEmptyString, type: "detection" | "rule_default" | "endpoint" | "endpoint_trusted_apps" | "endpoint_events" | "endpoint_host_isolation_exceptions" | "endpoint_blocklists", namespace_type: "agnostic" | "single" |}>"', + ]); + expect(message.schema).toEqual({}); + }); + }); + + describe('listArrayOrUndefined', () => { + test('it should validate an array of lists', () => { + const payload = getListArrayMock(); + const decoded = listArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate when undefined', () => { + const payload = undefined; + const decoded = listArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an item that is not of type "list" in array', () => { + const payload = [1] as unknown as ListArrayOrUndefined; + const decoded = listArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "(Array<{| id: NonEmptyString, list_id: NonEmptyString, type: "detection" | "rule_default" | "endpoint" | "endpoint_trusted_apps" | "endpoint_events" | "endpoint_host_isolation_exceptions" | "endpoint_blocklists", namespace_type: "agnostic" | "single" |}> | undefined)"', + 'Invalid value "[1]" supplied to "(Array<{| id: NonEmptyString, list_id: NonEmptyString, type: "detection" | "rule_default" | "endpoint" | "endpoint_trusted_apps" | "endpoint_events" | "endpoint_host_isolation_exceptions" | "endpoint_blocklists", namespace_type: "agnostic" | "single" |}> | undefined)"', + ]); + expect(message.schema).toEqual({}); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.ts new file mode 100644 index 0000000000000..bbc99142ffc7b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; +import { exceptionListType } from '../exception_list'; +import { namespaceType } from '../default_namespace'; + +export const list = t.exact( + t.type({ + id: NonEmptyString, + list_id: NonEmptyString, + type: exceptionListType, + namespace_type: namespaceType, + }) +); + +export type List = t.TypeOf; +export const listArray = t.array(list); +export type ListArray = t.TypeOf; +export const listArrayOrUndefined = t.union([listArray, t.undefined]); +export type ListArrayOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.test.ts new file mode 100644 index 0000000000000..b702f617d17c7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.test.ts @@ -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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { DefaultListArray } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getListArrayMock } from '../lists/index.mock'; + +describe('lists_default_array', () => { + test('it should return a default array when null', () => { + const payload = null; + const decoded = DefaultListArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([]); + }); + + test('it should return a default array when undefined', () => { + const payload = undefined; + const decoded = DefaultListArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([]); + }); + + test('it should validate an empty array', () => { + const payload: string[] = []; + const decoded = DefaultListArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of lists', () => { + const payload = getListArrayMock(); + const decoded = DefaultListArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not validate an array of non accepted types', () => { + // Terrible casting for purpose of tests + const payload = [1] as unknown; + const decoded = DefaultListArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "DefaultListArray"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.ts new file mode 100644 index 0000000000000..33ab281a6f176 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/lists_default_array/index.ts @@ -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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { list, ListArray } from '../lists'; + +/** + * Types the DefaultListArray as: + * - If null or undefined, then a default array of type list will be set + */ +export const DefaultListArray = new t.Type( + 'DefaultListArray', + t.array(list).is, + (input, context): Either => + input == null ? t.success([]) : t.array(list).validate(input, context), + t.identity +); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.test.ts new file mode 100644 index 0000000000000..2c733c93ee778 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.test.ts @@ -0,0 +1,56 @@ +/* + * 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 { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { maxSizeOrUndefined } from '.'; + +import { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; + +describe('maxSizeOrUndefined', () => { + test('it will validate a correct max value', () => { + const payload = 123; + const decoded = maxSizeOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will fail to validate a 0', () => { + const payload = 0; + const decoded = maxSizeOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "0" supplied to "(PositiveIntegerGreaterThanZero | undefined)"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it will fail to validate a -1', () => { + const payload = -1; + const decoded = maxSizeOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "-1" supplied to "(PositiveIntegerGreaterThanZero | undefined)"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it will fail to validate a string', () => { + const payload = '123'; + const decoded = maxSizeOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "123" supplied to "(PositiveIntegerGreaterThanZero | undefined)"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.ts new file mode 100644 index 0000000000000..c652ae81d6c41 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/max_size/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import { PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; +import * as t from 'io-ts'; + +export const max_size = PositiveIntegerGreaterThanZero; +export type MaxSize = t.TypeOf; + +export const maxSizeOrUndefined = t.union([max_size, t.undefined]); +export type MaxSizeOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/meta/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/meta/index.ts new file mode 100644 index 0000000000000..547b45969be71 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/meta/index.ts @@ -0,0 +1,16 @@ +/* + * 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 * as t from 'io-ts'; + +export const meta = t.object; +export type Meta = t.TypeOf; +export const metaOrUndefined = t.union([meta, t.undefined]); +export type MetaOrUndefined = t.TypeOf; + +export const nullableMetaOrUndefined = t.union([metaOrUndefined, t.null]); +export type NullableMetaOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/name/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/name/index.ts new file mode 100644 index 0000000000000..020f3642306a9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/name/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const name = t.string; +export type Name = t.TypeOf; +export const nameOrUndefined = t.union([name, t.undefined]); +export type NameOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/namespace_type/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/namespace_type/index.ts new file mode 100644 index 0000000000000..ae16f8b4521ca --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/namespace_type/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import { DefaultNamespace } from '../default_namespace'; + +export const namespace_type = DefaultNamespace; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.test.ts new file mode 100644 index 0000000000000..321a57dd4feea --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.test.ts @@ -0,0 +1,130 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { EntriesArray } from '../entries'; +import { nonEmptyEntriesArray } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getEntryMatchMock } from '../entry_match/index.mock'; +import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; +import { getEntryExistsMock } from '../entries_exist/index.mock'; +import { + getEntriesArrayMock, + getListAndNonListEntriesArrayMock, + getListEntriesArrayMock, +} from '../entries/index.mock'; +import { getEntryNestedMock } from '../entry_nested/index.mock'; + +describe('non_empty_entries_array', () => { + test('it should FAIL validation when given an empty array', () => { + const payload: EntriesArray = []; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "[]" supplied to "NonEmptyEntriesArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when given "undefined"', () => { + const payload = undefined; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "NonEmptyEntriesArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when given "null"', () => { + const payload = null; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "null" supplied to "NonEmptyEntriesArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should validate an array of "match" entries', () => { + const payload: EntriesArray = [getEntryMatchMock(), getEntryMatchMock()]; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of "match_any" entries', () => { + const payload: EntriesArray = [getEntryMatchAnyMock(), getEntryMatchAnyMock()]; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of "exists" entries', () => { + const payload: EntriesArray = [getEntryExistsMock(), getEntryExistsMock()]; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of "list" entries', () => { + const payload: EntriesArray = [...getListEntriesArrayMock()]; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of "nested" entries', () => { + const payload: EntriesArray = [getEntryNestedMock(), getEntryNestedMock()]; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of entries', () => { + const payload: EntriesArray = [...getEntriesArrayMock()]; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when given an array of entries of value list and non-value list entries', () => { + const payload: EntriesArray = [...getListAndNonListEntriesArrayMock()]; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Cannot have entry of type list and other']); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when given an array of non entries', () => { + const payload = [1]; + const decoded = nonEmptyEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "NonEmptyEntriesArray"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.ts new file mode 100644 index 0000000000000..8d6812077d4e2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_entries_array/index.ts @@ -0,0 +1,40 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { entriesArray, EntriesArray } from '../entries'; +import { entriesList } from '../entries_list'; + +/** + * Types the nonEmptyEntriesArray as: + * - An array of entries of length 1 or greater + * + */ +export const nonEmptyEntriesArray = new t.Type( + 'NonEmptyEntriesArray', + entriesArray.is, + (input, context): Either => { + if (Array.isArray(input) && input.length === 0) { + return t.failure(input, context); + } else { + if ( + Array.isArray(input) && + input.some((entry) => entriesList.is(entry)) && + input.some((entry) => !entriesList.is(entry)) + ) { + // fail when an exception item contains both a value list entry and a non-value list entry + return t.failure(input, context, 'Cannot have entry of type list and other'); + } + return entriesArray.validate(input, context); + } + }, + t.identity +); + +export type NonEmptyEntriesArray = t.OutputOf; +export type NonEmptyEntriesArrayDecoded = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.test.ts new file mode 100644 index 0000000000000..1d1d659f028c4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.test.ts @@ -0,0 +1,115 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { EntriesArray } from '../entries'; +import { nonEmptyNestedEntriesArray } from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getEntryMatchMock } from '../entry_match/index.mock'; +import { getEntryMatchAnyMock } from '../entry_match_any/index.mock'; +import { getEntryExistsMock } from '../entries_exist/index.mock'; +import { getEntryNestedMock } from '../entry_nested/index.mock'; + +describe('non_empty_nested_entries_array', () => { + test('it should FAIL validation when given an empty array', () => { + const payload: EntriesArray = []; + const decoded = nonEmptyNestedEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "[]" supplied to "NonEmptyNestedEntriesArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when given "undefined"', () => { + const payload = undefined; + const decoded = nonEmptyNestedEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "NonEmptyNestedEntriesArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should FAIL validation when given "null"', () => { + const payload = null; + const decoded = nonEmptyNestedEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "null" supplied to "NonEmptyNestedEntriesArray"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should validate an array of "match" entries', () => { + const payload: EntriesArray = [getEntryMatchMock(), getEntryMatchMock()]; + const decoded = nonEmptyNestedEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of "match_any" entries', () => { + const payload: EntriesArray = [getEntryMatchAnyMock(), getEntryMatchAnyMock()]; + const decoded = nonEmptyNestedEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate an array of "exists" entries', () => { + const payload: EntriesArray = [getEntryExistsMock(), getEntryExistsMock()]; + const decoded = nonEmptyNestedEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when given an array of "nested" entries', () => { + const payload: EntriesArray = [getEntryNestedMock(), getEntryNestedMock()]; + const decoded = nonEmptyNestedEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "operator"', + 'Invalid value "nested" supplied to "type"', + 'Invalid value "undefined" supplied to "value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should validate an array of entries', () => { + const payload: EntriesArray = [ + getEntryExistsMock(), + getEntryMatchAnyMock(), + getEntryMatchMock(), + ]; + const decoded = nonEmptyNestedEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should FAIL validation when given an array of non entries', () => { + const payload = [1]; + const decoded = nonEmptyNestedEntriesArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "NonEmptyNestedEntriesArray"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.ts new file mode 100644 index 0000000000000..eb2d1074b9f44 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/non_empty_nested_entries_array/index.ts @@ -0,0 +1,41 @@ +/* + * 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 * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { entriesMatch } from '../entry_match'; +import { entriesMatchAny } from '../entry_match_any'; +import { entriesExists } from '../entries_exist'; + +export const nestedEntryItem = t.union([entriesMatch, entriesMatchAny, entriesExists]); +export const nestedEntriesArray = t.array(nestedEntryItem); +export type NestedEntriesArray = t.TypeOf; + +/** + * Types the nonEmptyNestedEntriesArray as: + * - An array of entries of length 1 or greater + * + */ +export const nonEmptyNestedEntriesArray = new t.Type< + NestedEntriesArray, + NestedEntriesArray, + unknown +>( + 'NonEmptyNestedEntriesArray', + nestedEntriesArray.is, + (input, context): Either => { + if (Array.isArray(input) && input.length === 0) { + return t.failure(input, context); + } else { + return nestedEntriesArray.validate(input, context); + } + }, + t.identity +); + +export type NonEmptyNestedEntriesArray = t.OutputOf; +export type NonEmptyNestedEntriesArrayDecoded = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.test.ts new file mode 100644 index 0000000000000..3b8ca29afa4e9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.test.ts @@ -0,0 +1,43 @@ +/* + * 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 { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { osType, osTypeArrayOrUndefined } from '.'; + +import { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; + +describe('osType', () => { + test('it will validate a correct osType', () => { + const payload = 'windows'; + const decoded = osType.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will fail to validate an incorrect osType', () => { + const payload = 'foo'; + const decoded = osType.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "foo" supplied to ""linux" | "macos" | "windows""', + ]); + expect(message.schema).toEqual({}); + }); + + test('it will default to an empty array when osTypeArrayOrUndefined is used', () => { + const payload = undefined; + const decoded = osTypeArrayOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual([]); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.ts new file mode 100644 index 0000000000000..6e8cbb85b6312 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/os_type/index.ts @@ -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 * as t from 'io-ts'; +import { DefaultArray } from '@kbn/securitysolution-io-ts-types'; + +export const osType = t.keyof({ + linux: null, + macos: null, + windows: null, +}); +export type OsType = t.TypeOf; + +export const osTypeArray = DefaultArray(osType); +export type OsTypeArray = t.TypeOf; + +export const osTypeArrayOrUndefined = t.union([osTypeArray, t.undefined]); +export type OsTypeArrayOrUndefined = t.OutputOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/page/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/page/index.ts new file mode 100644 index 0000000000000..36faf8e7e5e24 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/page/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const page = t.number; // TODO: Change this out for PositiveNumber from siem +export type Page = t.TypeOf; + +export const pageOrUndefined = t.union([page, t.undefined]); +export type PageOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/per_page/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/per_page/index.ts new file mode 100644 index 0000000000000..669e0699b366c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/per_page/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const per_page = t.number; // TODO: Change this out for PositiveNumber from siem +export type PerPage = t.TypeOf; + +export const perPageOrUndefined = t.union([per_page, t.undefined]); +export type PerPageOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.test.ts new file mode 100644 index 0000000000000..9cafd8ed5ec0f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.test.ts @@ -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 { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { pitOrUndefined } from '.'; + +import * as t from 'io-ts'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; + +describe('pitOrUndefined', () => { + test('it will validate a correct pit', () => { + const payload = { id: '123', keepAlive: '1m' }; + const decoded = pitOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will validate with the value of "undefined"', () => { + const obj = t.exact( + t.type({ + pit_id: pitOrUndefined, + }) + ); + const payload: t.TypeOf = { + pit_id: undefined, + }; + const decoded = obj.decode({ + pit_id: undefined, + }); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will validate a correct pit without having a "keepAlive"', () => { + const payload = { id: '123' }; + const decoded = pitOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will fail to validate an incorrect pit', () => { + const payload = 'foo'; + const decoded = pitOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "foo" supplied to "({| id: string, keepAlive: (string | undefined) |} | undefined)"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.ts new file mode 100644 index 0000000000000..97b6957e07e53 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/pit/index.ts @@ -0,0 +1,21 @@ +/* + * 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 * as t from 'io-ts'; + +export const pitId = t.string; +export const pit = t.exact( + t.type({ + id: pitId, + keepAlive: t.union([t.string, t.undefined]), + }) +); +export const pitOrUndefined = t.union([pit, t.undefined]); + +export type Pit = t.TypeOf; +export type PitId = t.TypeOf; +export type PitOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/refresh/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/refresh/index.ts new file mode 100644 index 0000000000000..d1a7fe34fc704 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/refresh/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * as t from 'io-ts'; + +export const refresh = t.union([t.literal('true'), t.literal('false')]); +export const refreshWithWaitFor = t.union([ + t.literal('true'), + t.literal('false'), + t.literal('wait_for'), +]); +export type Refresh = t.TypeOf; +export type RefreshWithWaitFor = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/required_keep_undefined/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/required_keep_undefined/index.ts new file mode 100644 index 0000000000000..5854fc42a3a78 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/required_keep_undefined/index.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/** + * This makes any optional property the same as Required would but also has the + * added benefit of keeping your undefined. + * + * For example: + * type A = RequiredKeepUndefined<{ a?: undefined; b: number }>; + * + * will yield a type of: + * type A = { a: undefined; b: number; } + * @deprecated This has no replacement. We should stop using/relying on this and just remove it. + */ +export type RequiredKeepUndefined = { [K in keyof T]-?: [T[K]] } extends infer U + ? U extends Record + ? { [K in keyof U]: U[K][0] } + : never + : never; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.test.ts new file mode 100644 index 0000000000000..6c45f50c9c894 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.test.ts @@ -0,0 +1,53 @@ +/* + * 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 { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { searchOrUndefined } from '.'; + +import * as t from 'io-ts'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; + +describe('search', () => { + test('it will validate a correct search', () => { + const payload = 'name:foo'; + const decoded = searchOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will validate with the value of "undefined"', () => { + const obj = t.exact( + t.type({ + search: searchOrUndefined, + }) + ); + const payload: t.TypeOf = { + search: undefined, + }; + const decoded = obj.decode({ + pit_id: undefined, + }); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will fail to validate an incorrect search', () => { + const payload = ['foo']; + const decoded = searchOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "["foo"]" supplied to "(string | undefined)"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.ts new file mode 100644 index 0000000000000..b93c4631cd223 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const search = t.string; +export type Search = t.TypeOf; + +export const searchOrUndefined = t.union([search, t.undefined]); +export type SearchOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.test.ts new file mode 100644 index 0000000000000..bc176af4fa307 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.test.ts @@ -0,0 +1,53 @@ +/* + * 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 { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { searchAfterOrUndefined } from '.'; + +import * as t from 'io-ts'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; + +describe('searchAfter', () => { + test('it will validate a correct search_after', () => { + const payload = ['test-1', 'test-2']; + const decoded = searchAfterOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will validate with the value of "undefined"', () => { + const obj = t.exact( + t.type({ + search_after: searchAfterOrUndefined, + }) + ); + const payload: t.TypeOf = { + search_after: undefined, + }; + const decoded = obj.decode({ + pit_id: undefined, + }); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will fail to validate an incorrect search_after', () => { + const payload = 'foo'; + const decoded = searchAfterOrUndefined.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "foo" supplied to "(Array | undefined)"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.ts new file mode 100644 index 0000000000000..17735728d3418 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/search_after/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const search_after = t.array(t.string); +export type SearchAfter = t.TypeOf; + +export const searchAfterOrUndefined = t.union([search_after, t.undefined]); +export type SearchAfterOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/serializer/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/serializer/index.ts new file mode 100644 index 0000000000000..28322ff2e9910 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/serializer/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const serializer = t.string; +export type Serializer = t.TypeOf; +export const serializerOrUndefined = t.union([serializer, t.undefined]); +export type SerializerOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_field/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_field/index.ts new file mode 100644 index 0000000000000..762fdf80c227d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_field/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const sort_field = t.string; +export const sortFieldOrUndefined = t.union([sort_field, t.undefined]); +export type SortFieldOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_order/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_order/index.ts new file mode 100644 index 0000000000000..a849e45c316ea --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/sort_order/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const sort_order = t.keyof({ asc: null, desc: null }); +export const sortOrderOrUndefined = t.union([sort_order, t.undefined]); +export type SortOrderOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/tags/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/tags/index.ts new file mode 100644 index 0000000000000..0ad756f057718 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/tags/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +import { DefaultStringArray } from '@kbn/securitysolution-io-ts-types'; + +export const tags = DefaultStringArray; +export type Tags = t.TypeOf; +export const tagsOrUndefined = t.union([tags, t.undefined]); +export type TagsOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/tie_breaker_id/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/tie_breaker_id/index.ts new file mode 100644 index 0000000000000..362e500890818 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/tie_breaker_id/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const tie_breaker_id = t.string; // TODO: Use UUID for this instead of a string for validation diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/timestamp/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/timestamp/index.ts new file mode 100644 index 0000000000000..30472bcd101f9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/timestamp/index.ts @@ -0,0 +1,12 @@ +/* + * 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 * as t from 'io-ts'; +import { IsoDateString } from '@kbn/securitysolution-io-ts-types'; + +export const timestamp = IsoDateString; +export const timestampOrUndefined = t.union([IsoDateString, t.undefined]); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/total/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/total/index.ts new file mode 100644 index 0000000000000..f67ca0f2fc5e5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/total/index.ts @@ -0,0 +1,12 @@ +/* + * 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 * as t from 'io-ts'; + +export const total = t.number; // TODO: Change this out for PositiveNumber from siem +export const totalUndefined = t.union([total, t.undefined]); +export type TotalOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.test.ts new file mode 100644 index 0000000000000..d87ea94728b13 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.test.ts @@ -0,0 +1,33 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { Type, type } from '.'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('type', () => { + test('it will work with a given expected type', () => { + const payload: Type = 'keyword'; + const decoded = type.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it will give an error if given a type that does not exist', () => { + const payload: Type | 'madeup' = 'madeup'; + const decoded = type.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "madeup" supplied to ""binary" | "boolean" | "byte" | "date" | "date_nanos" | "date_range" | "double" | "double_range" | "float" | "float_range" | "geo_point" | "geo_shape" | "half_float" | "integer" | "integer_range" | "ip" | "ip_range" | "keyword" | "long" | "long_range" | "shape" | "short" | "text""', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.ts new file mode 100644 index 0000000000000..5a1d234d5f2fc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/type/index.ts @@ -0,0 +1,42 @@ +/* + * 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 * as t from 'io-ts'; + +/** + * Types of all the regular single value list items but not exception list + * or exception list types. Those types are in the list_types folder. + */ +export const type = t.keyof({ + binary: null, + boolean: null, + byte: null, + date: null, + date_nanos: null, + date_range: null, + double: null, + double_range: null, + float: null, + float_range: null, + geo_point: null, + geo_shape: null, + half_float: null, + integer: null, + integer_range: null, + ip: null, + ip_range: null, + keyword: null, + long: null, + long_range: null, + shape: null, + short: null, + text: null, +}); + +export const typeOrUndefined = t.union([type, t.undefined]); +export type Type = t.TypeOf; +export type TypeOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/underscore_version/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/underscore_version/index.ts new file mode 100644 index 0000000000000..6e47b89af8163 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/underscore_version/index.ts @@ -0,0 +1,12 @@ +/* + * 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 * as t from 'io-ts'; + +export const _version = t.string; +export const _versionOrUndefined = t.union([_version, t.undefined]); +export type _VersionOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.mock.ts new file mode 100644 index 0000000000000..c0cbfe5e3019c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.mock.ts @@ -0,0 +1,19 @@ +/* + * 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 { UpdateComment, UpdateCommentsArray } from '.'; +import { ID } from '../../constants/index.mock'; + +export const getUpdateCommentMock = (): UpdateComment => ({ + comment: 'some comment', + id: ID, +}); + +export const getUpdateCommentsArrayMock = (): UpdateCommentsArray => [ + getUpdateCommentMock(), + getUpdateCommentMock(), +]; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.test.ts new file mode 100644 index 0000000000000..c1f1be8be9c1c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.test.ts @@ -0,0 +1,148 @@ +/* + * 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 { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { getUpdateCommentMock, getUpdateCommentsArrayMock } from './index.mock'; +import { + UpdateComment, + updateComment, + UpdateCommentsArray, + updateCommentsArray, + UpdateCommentsArrayOrUndefined, + updateCommentsArrayOrUndefined, +} from '.'; +import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +describe('UpdateComment', () => { + describe('updateComment', () => { + test('it should pass validation when supplied typical comment update', () => { + const payload = getUpdateCommentMock(); + const decoded = updateComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when supplied an undefined for "comment"', () => { + const payload = getUpdateCommentMock(); + // @ts-expect-error + delete payload.comment; + const decoded = updateComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "comment"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an empty string for "comment"', () => { + const payload = { ...getUpdateCommentMock(), comment: '' }; + const decoded = updateComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "comment"']); + expect(message.schema).toEqual({}); + }); + + test('it should pass validation when supplied an undefined for "id"', () => { + const payload = getUpdateCommentMock(); + delete payload.id; + const decoded = updateComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when supplied an empty string for "id"', () => { + const payload = { ...getUpdateCommentMock(), id: '' }; + const decoded = updateComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should strip out extra key passed in', () => { + const payload: UpdateComment & { + extraKey?: string; + } = { ...getUpdateCommentMock(), extraKey: 'some new value' }; + const decoded = updateComment.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getUpdateCommentMock()); + }); + }); + + describe('updateCommentsArray', () => { + test('it should pass validation when supplied an array of comments', () => { + const payload = getUpdateCommentsArrayMock(); + const decoded = updateCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when undefined', () => { + const payload = undefined; + const decoded = updateCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "Array<({| comment: NonEmptyString |} & Partial<{| id: NonEmptyString |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when array includes non comments types', () => { + const payload = [1] as unknown as UpdateCommentsArray; + const decoded = updateCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString |} & Partial<{| id: NonEmptyString |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + }); + + describe('updateCommentsArrayOrUndefined', () => { + test('it should pass validation when supplied an array of comments', () => { + const payload = getUpdateCommentsArrayMock(); + const decoded = updateCommentsArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should pass validation when supplied when undefined', () => { + const payload = undefined; + const decoded = updateCommentsArrayOrUndefined.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when array includes non comments types', () => { + const payload = [1] as unknown as UpdateCommentsArrayOrUndefined; + const decoded = updateCommentsArray.decode(payload); + const message = pipe(decoded, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "1" supplied to "Array<({| comment: NonEmptyString |} & Partial<{| id: NonEmptyString |}>)>"', + ]); + expect(message.schema).toEqual({}); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.ts new file mode 100644 index 0000000000000..6a0b4b08c7722 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/update_comment/index.ts @@ -0,0 +1,29 @@ +/* + * 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 * as t from 'io-ts'; +import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; +import { id } from '../id'; + +export const updateComment = t.intersection([ + t.exact( + t.type({ + comment: NonEmptyString, + }) + ), + t.exact( + t.partial({ + id, + }) + ), +]); + +export type UpdateComment = t.TypeOf; +export const updateCommentsArray = t.array(updateComment); +export type UpdateCommentsArray = t.TypeOf; +export const updateCommentsArrayOrUndefined = t.union([updateCommentsArray, t.undefined]); +export type UpdateCommentsArrayOrUndefined = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_at/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_at/index.ts new file mode 100644 index 0000000000000..bafbadcd8f09b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_at/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const updated_at = t.string; // TODO: Make this into an ISO Date string check diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_by/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_by/index.ts new file mode 100644 index 0000000000000..58c5b2d666bd8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/updated_by/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import * as t from 'io-ts'; + +export const updated_by = t.string; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/value/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/value/index.ts new file mode 100644 index 0000000000000..38530a942275c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/common/value/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const value = t.string; +export const valueOrUndefined = t.union([value, t.undefined]); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/constants/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/constants/index.mock.ts new file mode 100644 index 0000000000000..ae91d63d6b7e3 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/constants/index.mock.ts @@ -0,0 +1,113 @@ +/* + * 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 { EndpointEntriesArray } from '../common/endpoint/entries'; +import { EntriesArray, Entry } from '../common/entries'; +import { EntryMatch } from '../common/entry_match'; +import { EntryNested } from '../common/entry_nested'; +import { OsTypeArray } from '../common/os_type'; + +export const DATE_NOW = '2020-04-20T15:25:31.830Z'; +export const OLD_DATE_RELATIVE_TO_DATE_NOW = '2020-04-19T15:25:31.830Z'; +export const USER = 'some user'; +export const ELASTIC_USER = 'elastic'; +export const LIST_INDEX = '.lists'; +export const LIST_ITEM_INDEX = '.items'; +export const NAME = 'some name'; +export const DESCRIPTION = 'some description'; +export const LIST_ID = 'some-list-id'; +export const LIST_ITEM_ID = 'some-list-item-id'; +export const TIE_BREAKER = '6a76b69d-80df-4ab2-8c3e-85f466b06a0e'; +export const TIE_BREAKERS = [ + '21530991-4051-46ec-bc35-2afa09a1b0b5', + '3c662054-ae37-4aa9-9936-3e8e2ea26775', + '60e49a20-3a23-48b6-8bf9-ed5e3b70f7a0', + '38814080-a40f-4358-992a-3b875f9b7dec', + '29fa61be-aaaf-411c-a78a-7059e3f723f1', + '9c19c959-cb9d-4cd2-99e4-1ea2baf0ef0e', + 'd409308c-f94b-4b3a-8234-bbd7a80c9140', + '87824c99-cd83-45c4-8aa6-4ad95dfea62c', + '7b940c17-9355-479f-b882-f3e575718f79', + '5983ad0c-4ef4-4fa0-8308-80ab9ecc4f74', +]; +export const META = {}; +export const TYPE = 'ip'; +export const VALUE = '127.0.0.1'; +export const VALUE_2 = '255.255.255'; +export const NAMESPACE_TYPE = 'single'; +export const NESTED_FIELD = 'parent.field'; + +// Exception List specific +export const ID = 'uuid_here'; +export const ITEM_ID = 'some-list-item-id'; +export const DETECTION_TYPE = 'detection'; +export const ENDPOINT_TYPE = 'endpoint'; +export const FIELD = 'host.name'; +export const OPERATOR = 'included'; +export const OPERATOR_EXCLUDED = 'excluded'; +export const ENTRY_VALUE = 'some host name'; +export const MATCH = 'match'; +export const MATCH_ANY = 'match_any'; +export const WILDCARD = 'wildcard'; +export const MAX_IMPORT_PAYLOAD_BYTES = 9000000; +export const IMPORT_BUFFER_SIZE = 1000; +export const LIST = 'list'; +export const EXISTS = 'exists'; +export const NESTED = 'nested'; +export const ENTRIES: EntriesArray = [ + { + entries: [{ field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }], + field: 'some.parentField', + type: 'nested', + }, + { field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' }, +]; +export const ENDPOINT_ENTRIES: EndpointEntriesArray = [ + { + entries: [{ field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }], + field: 'some.parentField', + type: 'nested', + }, + { field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' }, +]; +// ENTRIES_WITH_IDS should only be used to mock out functionality of a collection of transforms +// that are UI specific and useful for UI concerns that are inserted between the +// API and the actual user interface. In some ways these might be viewed as +// technical debt or to compensate for the differences and preferences +// of how ReactJS might prefer data vs. how we want to model data. +export const ENTRIES_WITH_IDS: EntriesArray = [ + { + entries: [ + { + field: 'nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as EntryMatch & { id: string }, + ], + field: 'some.parentField', + id: '123', + type: 'nested', + } as EntryNested & { id: string }, + { + field: 'some.not.nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as Entry & { id: string }, +]; +export const ITEM_TYPE = 'simple'; +export const OS_TYPES: OsTypeArray = ['windows']; +export const TAGS = []; +export const COMMENTS = []; +export const FILTER = 'name:Nicolas Bourbaki'; +export const CURSOR = 'c29tZXN0cmluZ2ZvcnlvdQ=='; +export const _VERSION = 'WzI5NywxXQ=='; +export const VERSION = 1; +export const IMMUTABLE = false; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..0efac9d4de7f5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.mock.ts @@ -0,0 +1,30 @@ +/* + * 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 { CreateEndpointListItemSchema } from '.'; +import { + COMMENTS, + DESCRIPTION, + ENDPOINT_ENTRIES, + ITEM_TYPE, + META, + NAME, + OS_TYPES, + TAGS, +} from '../../constants/index.mock'; + +export const getCreateEndpointListItemSchemaMock = (): CreateEndpointListItemSchema => ({ + comments: COMMENTS, + description: DESCRIPTION, + entries: ENDPOINT_ENTRIES, + item_id: undefined, + meta: META, + name: NAME, + os_types: OS_TYPES, + tags: TAGS, + type: ITEM_TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..78d578dd5d475 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.test.ts @@ -0,0 +1,205 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { getCreateEndpointListItemSchemaMock } from './index.mock'; +import { CreateEndpointListItemSchema, createEndpointListItemSchema } from '.'; +import { getCreateCommentsArrayMock } from '../../common/create_comment/index.mock'; +import { getCommentsMock } from '../../common/comment/index.mock'; +import { CommentsArray } from '../../common/comment'; + +describe('create_endpoint_list_item_schema', () => { + test('it should pass validation when supplied a typical list item request not counting the auto generated uuid', () => { + const payload = getCreateEndpointListItemSchemaMock(); + const decoded = createEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateEndpointListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when supplied an undefined for "description"', () => { + const payload = getCreateEndpointListItemSchemaMock(); + // @ts-expect-error + delete payload.description; + const decoded = createEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an undefined for "name"', () => { + const payload = getCreateEndpointListItemSchemaMock(); + // @ts-expect-error + delete payload.name; + const decoded = createEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an undefined for "type"', () => { + const payload = getCreateEndpointListItemSchemaMock(); + // @ts-expect-error + delete payload.type; + const decoded = createEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied a "list_id" since it does not required one', () => { + const inputPayload: CreateEndpointListItemSchema & { list_id: string } = { + ...getCreateEndpointListItemSchemaMock(), + list_id: 'list-123', + }; + const decoded = createEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "list_id"']); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied a "namespace_type" since it does not required one', () => { + const inputPayload: CreateEndpointListItemSchema & { namespace_type: string } = { + ...getCreateEndpointListItemSchemaMock(), + namespace_type: 'single', + }; + const decoded = createEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "namespace_type"']); + expect(message.schema).toEqual({}); + }); + + test('it should pass validation when supplied an undefined for "meta" but strip it out and generate a correct body not counting the auto generated uuid', () => { + const payload = getCreateEndpointListItemSchemaMock(); + const outputPayload = getCreateEndpointListItemSchemaMock(); + delete payload.meta; + delete outputPayload.meta; + const decoded = createEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateEndpointListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should pass validation when supplied an undefined for "comments" but return an array and generate a correct body not counting the auto generated uuid', () => { + const inputPayload = getCreateEndpointListItemSchemaMock(); + const outputPayload = getCreateEndpointListItemSchemaMock(); + delete inputPayload.comments; + outputPayload.comments = []; + const decoded = createEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateEndpointListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should pass validation when supplied "comments" array', () => { + const inputPayload = { + ...getCreateEndpointListItemSchemaMock(), + comments: getCreateCommentsArrayMock(), + }; + const decoded = createEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateEndpointListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(inputPayload); + }); + + test('it should fail validation when supplied "comments" with "created_at", "created_by", or "id" values', () => { + const inputPayload: Omit & { + comments?: CommentsArray; + } = { + ...getCreateEndpointListItemSchemaMock(), + comments: [getCommentsMock()], + }; + const decoded = createEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "created_at,created_by,id"']); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an undefined for "entries"', () => { + const inputPayload = getCreateEndpointListItemSchemaMock(); + const outputPayload = getCreateEndpointListItemSchemaMock(); + // @ts-expect-error + delete inputPayload.entries; + outputPayload.entries = []; + const decoded = createEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateEndpointListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should pass validation when supplied an undefined for "tags" but return an array and generate a correct body not counting the auto generated uuid', () => { + const inputPayload = getCreateEndpointListItemSchemaMock(); + const outputPayload = getCreateEndpointListItemSchemaMock(); + delete inputPayload.tags; + outputPayload.tags = []; + const decoded = createEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateEndpointListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should pass validation when supplied an undefined for "item_id" and auto generate a uuid', () => { + const inputPayload = getCreateEndpointListItemSchemaMock(); + delete inputPayload.item_id; + const decoded = createEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect((message.schema as CreateEndpointListItemSchema).item_id).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i + ); + }); + + test('it should pass validation when supplied an undefined for "item_id" and generate a correct body not counting the uuid', () => { + const inputPayload = getCreateEndpointListItemSchemaMock(); + delete inputPayload.item_id; + const decoded = createEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateEndpointListItemSchema).item_id; + expect(message.schema).toEqual(inputPayload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: CreateEndpointListItemSchema & { + extraKey: string; + } = { ...getCreateEndpointListItemSchemaMock(), extraKey: 'some new value' }; + const decoded = createEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.ts new file mode 100644 index 0000000000000..08fd5e339ade9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_endpoint_list_item_schema/index.ts @@ -0,0 +1,56 @@ +/* + * 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 * as t from 'io-ts'; + +import { DefaultUuid } from '@kbn/securitysolution-io-ts-types'; +import { nonEmptyEndpointEntriesArray } from '../../common/endpoint/entries'; +import { exceptionListItemType } from '../../common/exception_list_item_type'; +import { DefaultCreateCommentsArray } from '../../common/default_create_comments_array'; +import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { CreateCommentsArray } from '../../common/create_comment'; +import { Tags, tags } from '../../common/tags'; +import { ItemId } from '../../common/item_id'; +import { EntriesArray } from '../../common/entries'; +import { description } from '../../common/description'; +import { name } from '../../common/name'; +import { meta } from '../../common/meta'; + +export const createEndpointListItemSchema = t.intersection([ + t.exact( + t.type({ + description, + entries: nonEmptyEndpointEntriesArray, + name, + type: exceptionListItemType, + }) + ), + t.exact( + t.partial({ + comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode + item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode + meta, // defaults to undefined if not set during decode + os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode + tags, // defaults to empty array if not set during decode + }) + ), +]); + +export type CreateEndpointListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type CreateEndpointListItemSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'tags' | 'item_id' | 'entries' | 'comments' | 'os_types' +> & { + comments: CreateCommentsArray; + tags: Tags; + item_id: ItemId; + entries: EntriesArray; + os_types: OsTypeArray; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..4ccc82bf2af05 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.mock.ts @@ -0,0 +1,61 @@ +/* + * 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 { CreateExceptionListItemSchema } from '.'; +import { + COMMENTS, + DESCRIPTION, + ENTRIES, + ITEM_ID, + ITEM_TYPE, + LIST_ID, + META, + NAME, + NAMESPACE_TYPE, + OS_TYPES, + TAGS, +} from '../../constants/index.mock'; + +export const getCreateExceptionListItemSchemaMock = (): CreateExceptionListItemSchema => ({ + comments: COMMENTS, + description: DESCRIPTION, + entries: ENTRIES, + item_id: undefined, + list_id: LIST_ID, + meta: META, + name: NAME, + namespace_type: NAMESPACE_TYPE, + os_types: OS_TYPES, + tags: TAGS, + type: ITEM_TYPE, +}); + +/** + * Useful for end to end testing + */ +export const getCreateExceptionListItemMinimalSchemaMock = (): CreateExceptionListItemSchema => ({ + description: DESCRIPTION, + entries: ENTRIES, + item_id: ITEM_ID, + list_id: LIST_ID, + name: NAME, + os_types: OS_TYPES, + type: ITEM_TYPE, +}); + +/** + * Useful for end to end testing + */ +export const getCreateExceptionListItemMinimalSchemaMockWithoutId = + (): CreateExceptionListItemSchema => ({ + description: DESCRIPTION, + entries: ENTRIES, + list_id: LIST_ID, + name: NAME, + os_types: OS_TYPES, + type: ITEM_TYPE, + }); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..4d03b83112a3f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.test.ts @@ -0,0 +1,209 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getCreateExceptionListItemSchemaMock } from './index.mock'; +import { CreateExceptionListItemSchema, createExceptionListItemSchema } from '.'; +import { getCreateCommentsArrayMock } from '../../common/create_comment/index.mock'; +import { getCommentsMock } from '../../common/comment/index.mock'; +import { CommentsArray } from '../../common/comment'; + +describe('create_exception_list_item_schema', () => { + test('it should pass validation when supplied a typical exception list item request not counting the auto generated uuid', () => { + const payload = getCreateExceptionListItemSchemaMock(); + const decoded = createExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should fail validation when supplied an undefined for "description"', () => { + const payload = getCreateExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.description; + const decoded = createExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an undefined for "name"', () => { + const payload = getCreateExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.name; + const decoded = createExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an undefined for "type"', () => { + const payload = getCreateExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.type; + const decoded = createExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an undefined for "list_id"', () => { + const inputPayload = getCreateExceptionListItemSchemaMock(); + // @ts-expect-error + delete inputPayload.list_id; + const decoded = createExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should pass validation when supplied an undefined for "meta" but strip it out and generate a correct body not counting the auto generated uuid', () => { + const payload = getCreateExceptionListItemSchemaMock(); + const outputPayload = getCreateExceptionListItemSchemaMock(); + delete payload.meta; + delete outputPayload.meta; + const decoded = createExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should pass validation when supplied an undefined for "comments" but return an array and generate a correct body not counting the auto generated uuid', () => { + const inputPayload = getCreateExceptionListItemSchemaMock(); + const outputPayload = getCreateExceptionListItemSchemaMock(); + delete inputPayload.comments; + outputPayload.comments = []; + const decoded = createExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should pass validation when supplied "comments" array', () => { + const inputPayload = { + ...getCreateExceptionListItemSchemaMock(), + comments: getCreateCommentsArrayMock(), + }; + const decoded = createExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(inputPayload); + }); + + test('it should fail validation when supplied "comments" with "created_at" or "created_by" values', () => { + const inputPayload: Omit & { + comments?: CommentsArray; + } = { + ...getCreateExceptionListItemSchemaMock(), + comments: [getCommentsMock()], + }; + const decoded = createExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "created_at,created_by,id"']); + expect(message.schema).toEqual({}); + }); + + test('it should fail validation when supplied an undefined for "entries"', () => { + const inputPayload = getCreateExceptionListItemSchemaMock(); + const outputPayload = getCreateExceptionListItemSchemaMock(); + // @ts-expect-error + delete inputPayload.entries; + outputPayload.entries = []; + const decoded = createExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should pass validation when supplied an undefined for "namespace_type" but return enum "single" and generate a correct body not counting the auto generated uuid', () => { + const inputPayload = getCreateExceptionListItemSchemaMock(); + const outputPayload = getCreateExceptionListItemSchemaMock(); + delete inputPayload.namespace_type; + outputPayload.namespace_type = 'single'; + const decoded = createExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should pass validation when supplied an undefined for "tags" but return an array and generate a correct body not counting the auto generated uuid', () => { + const inputPayload = getCreateExceptionListItemSchemaMock(); + const outputPayload = getCreateExceptionListItemSchemaMock(); + delete inputPayload.tags; + outputPayload.tags = []; + const decoded = createExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListItemSchema).item_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should pass validation when supplied an undefined for "item_id" and auto generate a uuid', () => { + const inputPayload = getCreateExceptionListItemSchemaMock(); + delete inputPayload.item_id; + const decoded = createExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect((message.schema as CreateExceptionListItemSchema).item_id).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i + ); + }); + + test('it should pass validation when supplied an undefined for "item_id" and generate a correct body not counting the uuid', () => { + const inputPayload = getCreateExceptionListItemSchemaMock(); + delete inputPayload.item_id; + const decoded = createExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListItemSchema).item_id; + expect(message.schema).toEqual(inputPayload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: CreateExceptionListItemSchema & { + extraKey?: string; + } = getCreateExceptionListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = createExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.ts new file mode 100644 index 0000000000000..9276a0dafa8b5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_item_schema/index.ts @@ -0,0 +1,65 @@ +/* + * 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 * as t from 'io-ts'; +import { DefaultUuid } from '@kbn/securitysolution-io-ts-types'; + +import { DefaultCreateCommentsArray } from '../../common/default_create_comments_array'; +import { CreateCommentsArray } from '../../common/create_comment'; +import { Tags, tags } from '../../common/tags'; +import { ItemId } from '../../common/item_id'; +import { EntriesArray } from '../../common/entries'; +import { NamespaceType } from '../../common/default_namespace'; +import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { description } from '../../common/description'; +import { list_id } from '../../common/list_id'; +import { name } from '../../common/name'; +import { exceptionListItemType } from '../../common/exception_list_item_type'; +import { meta } from '../../common/meta'; +import { namespace_type } from '../../common/namespace_type'; +import { nonEmptyEntriesArray } from '../../common/non_empty_entries_array'; +import { ExpireTimeOrUndefined, expireTimeOrUndefined } from '../../common'; + +export const createExceptionListItemSchema = t.intersection([ + t.exact( + t.type({ + description, + entries: nonEmptyEntriesArray, + list_id, + name, + type: exceptionListItemType, + }) + ), + t.exact( + t.partial({ + comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode + expire_time: expireTimeOrUndefined, + item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode + meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode + os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode + tags, // defaults to empty array if not set during decode + }) + ), +]); + +export type CreateExceptionListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type CreateExceptionListItemSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments' | 'expire_time' +> & { + comments: CreateCommentsArray; + expire_time: ExpireTimeOrUndefined; + tags: Tags; + item_id: ItemId; + entries: EntriesArray; + namespace_type: NamespaceType; + os_types: OsTypeArray; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..2110a0056f0c4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.mock.ts @@ -0,0 +1,59 @@ +/* + * 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 { + DESCRIPTION, + ENDPOINT_TYPE, + LIST_ID, + META, + NAME, + NAMESPACE_TYPE, + VERSION, +} from '../../constants/index.mock'; + +import { CreateExceptionListSchema } from '.'; + +export const getCreateExceptionListSchemaMock = (): CreateExceptionListSchema => ({ + description: DESCRIPTION, + list_id: undefined, + meta: META, + name: NAME, + namespace_type: NAMESPACE_TYPE, + os_types: [], + tags: [], + type: ENDPOINT_TYPE, + version: VERSION, +}); + +/** + * Useful for end to end testing + */ +export const getCreateExceptionListMinimalSchemaMock = (): CreateExceptionListSchema => ({ + description: DESCRIPTION, + list_id: LIST_ID, + name: NAME, + type: ENDPOINT_TYPE, +}); + +/** + * Useful for end to end testing + */ +export const getCreateExceptionListMinimalSchemaMockWithoutId = (): CreateExceptionListSchema => ({ + description: DESCRIPTION, + name: NAME, + type: ENDPOINT_TYPE, +}); + +/** + * Useful for end to end testing with detections + */ +export const getCreateExceptionListDetectionSchemaMock = (): CreateExceptionListSchema => ({ + description: DESCRIPTION, + list_id: LIST_ID, + name: NAME, + type: 'detection', +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..26399804591e2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.test.ts @@ -0,0 +1,83 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { CreateExceptionListSchema, createExceptionListSchema } from '.'; +import { getCreateExceptionListSchemaMock } from './index.mock'; + +describe('create_exception_list_schema', () => { + test('it should validate a typical exception lists request and generate a correct body not counting the uuid', () => { + const payload = getCreateExceptionListSchemaMock(); + const decoded = createExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListSchema).list_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "meta" and generate a correct body not counting the uuid', () => { + const payload = getCreateExceptionListSchemaMock(); + delete payload.meta; + const decoded = createExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListSchema).list_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "tags" but return an array and generate a correct body not counting the uuid', () => { + const inputPayload = getCreateExceptionListSchemaMock(); + const outputPayload = getCreateExceptionListSchemaMock(); + delete inputPayload.tags; + outputPayload.tags = []; + const decoded = createExceptionListSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListSchema).list_id; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should accept an undefined for "list_id" and auto generate a uuid', () => { + const inputPayload = getCreateExceptionListSchemaMock(); + delete inputPayload.list_id; + const decoded = createExceptionListSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect((message.schema as CreateExceptionListSchema).list_id).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i + ); + }); + + test('it should accept an undefined for "list_id" and generate a correct body not counting the uuid', () => { + const inputPayload = getCreateExceptionListSchemaMock(); + delete inputPayload.list_id; + const decoded = createExceptionListSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as CreateExceptionListSchema).list_id; + expect(message.schema).toEqual(inputPayload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: CreateExceptionListSchema & { + extraKey?: string; + } = getCreateExceptionListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = createExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.ts new file mode 100644 index 0000000000000..000b4c65a01f4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_exception_list_schema/index.ts @@ -0,0 +1,58 @@ +/* + * 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 * as t from 'io-ts'; +import { + DefaultUuid, + DefaultVersionNumber, + DefaultVersionNumberDecoded, +} from '@kbn/securitysolution-io-ts-types'; + +import { exceptionListType } from '../../common/exception_list'; +import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { Tags, tags } from '../../common/tags'; +import { ListId } from '../../common/list_id'; +import { NamespaceType } from '../../common/default_namespace'; +import { name } from '../../common/name'; +import { description } from '../../common/description'; +import { namespace_type } from '../../common/namespace_type'; +import { meta } from '../../common/meta'; + +export const createExceptionListSchema = t.intersection([ + t.exact( + t.type({ + description, + name, + type: exceptionListType, + }) + ), + t.exact( + t.partial({ + list_id: DefaultUuid, // defaults to a GUID (UUID v4) string if not set during decode + meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode + os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode + tags, // defaults to empty array if not set during decode + version: DefaultVersionNumber, // defaults to numerical 1 if not set during decode + }) + ), +]); + +export type CreateExceptionListSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type CreateExceptionListSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'tags' | 'list_id' | 'namespace_type' | 'os_types' +> & { + tags: Tags; + list_id: ListId; + namespace_type: NamespaceType; + os_types: OsTypeArray; + version: DefaultVersionNumberDecoded; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..03085b3cfa8e7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.mock.ts @@ -0,0 +1,34 @@ +/* + * 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 { LIST_ID, LIST_ITEM_ID, META, VALUE } from '../../constants/index.mock'; + +import { CreateListItemSchema } from '.'; + +export const getCreateListItemSchemaMock = (): CreateListItemSchema => ({ + id: LIST_ITEM_ID, + list_id: LIST_ID, + meta: META, + value: VALUE, +}); + +/** + * Useful for end to end testing + */ +export const getCreateMinimalListItemSchemaMock = (): CreateListItemSchema => ({ + id: LIST_ITEM_ID, + list_id: LIST_ID, + value: VALUE, +}); + +/** + * Useful for end to end testing + */ +export const getCreateMinimalListItemSchemaMockWithoutId = (): CreateListItemSchema => ({ + list_id: LIST_ID, + value: VALUE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..509cbdbf0465a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.test.ts @@ -0,0 +1,57 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getCreateListItemSchemaMock } from './index.mock'; +import { CreateListItemSchema, createListItemSchema } from '.'; + +describe('create_list_item_schema', () => { + test('it should validate a typical list item request', () => { + const payload = getCreateListItemSchemaMock(); + const decoded = createListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for an id', () => { + const payload = getCreateListItemSchemaMock(); + delete payload.id; + const decoded = createListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for meta', () => { + const payload = getCreateListItemSchemaMock(); + delete payload.meta; + const decoded = createListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: CreateListItemSchema & { extraKey?: string } = getCreateListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = createListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.ts new file mode 100644 index 0000000000000..d18e7930c3eec --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_item_schema/index.ts @@ -0,0 +1,30 @@ +/* + * 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 * as t from 'io-ts'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { list_id } from '../../common/list_id'; +import { value } from '../../common/value'; +import { id } from '../../common/id'; +import { meta } from '../../common/meta'; +import { refreshWithWaitFor } from '../../common/refresh'; + +export const createListItemSchema = t.intersection([ + t.exact( + t.type({ + list_id, + value, + }) + ), + t.exact(t.partial({ id, meta, refresh: refreshWithWaitFor })), +]); + +export type CreateListItemSchema = t.OutputOf; +export type CreateListItemSchemaDecoded = RequiredKeepUndefined< + t.TypeOf +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.mock.ts new file mode 100644 index 0000000000000..aa4f45d74f4ad --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.mock.ts @@ -0,0 +1,40 @@ +/* + * 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 { DESCRIPTION, LIST_ID, META, NAME, TYPE, VERSION } from '../../constants/index.mock'; + +import { CreateListSchema } from '.'; + +export const getCreateListSchemaMock = (): CreateListSchema => ({ + description: DESCRIPTION, + deserializer: undefined, + id: LIST_ID, + meta: META, + name: NAME, + serializer: undefined, + type: TYPE, + version: VERSION, +}); + +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + */ +export const getCreateMinimalListSchemaMock = (): CreateListSchema => ({ + description: DESCRIPTION, + id: LIST_ID, + name: NAME, + type: TYPE, +}); + +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + */ +export const getCreateMinimalListSchemaMockWithoutId = (): CreateListSchema => ({ + description: DESCRIPTION, + name: NAME, + type: TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.test.ts new file mode 100644 index 0000000000000..a6043addd72a1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.test.ts @@ -0,0 +1,75 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { CreateListSchema, createListSchema } from '.'; +import { getCreateListSchemaMock } from './index.mock'; + +describe('create_list_schema', () => { + test('it should validate a typical lists request', () => { + const payload = getCreateListSchemaMock(); + const decoded = createListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for an id', () => { + const payload = getCreateListSchemaMock(); + delete payload.id; + const decoded = createListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for meta', () => { + const payload = getCreateListSchemaMock(); + delete payload.meta; + const decoded = createListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for serializer', () => { + const payload = getCreateListSchemaMock(); + delete payload.serializer; + const decoded = createListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for deserializer', () => { + const payload = getCreateListSchemaMock(); + delete payload.deserializer; + const decoded = createListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: CreateListSchema & { extraKey?: string } = getCreateListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = createListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.ts new file mode 100644 index 0000000000000..fd771d40a501c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_list_schema/index.ts @@ -0,0 +1,45 @@ +/* + * 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 * as t from 'io-ts'; +import { + DefaultVersionNumber, + DefaultVersionNumberDecoded, +} from '@kbn/securitysolution-io-ts-types'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { name } from '../../common/name'; +import { description } from '../../common/description'; +import { type } from '../../common/type'; +import { deserializer } from '../../common/deserializer'; +import { id } from '../../common/id'; +import { meta } from '../../common/meta'; +import { serializer } from '../../common/serializer'; + +export const createListSchema = t.intersection([ + t.exact( + t.type({ + description, + name, + type, + }) + ), + t.exact( + t.partial({ + deserializer, // defaults to undefined if not set during decode + id, // defaults to undefined if not set during decode + meta, // defaults to undefined if not set during decode + serializer, // defaults to undefined if not set during decode + version: DefaultVersionNumber, // defaults to a numerical 1 if not set during decode + }) + ), +]); + +export type CreateListSchema = t.OutputOf; +export type CreateListSchemaDecoded = RequiredKeepUndefined< + Omit, 'version'> +> & { version: DefaultVersionNumberDecoded }; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.test.ts new file mode 100644 index 0000000000000..bd95fdd0e0866 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.test.ts @@ -0,0 +1,125 @@ +/* + * 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 { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { left } from 'fp-ts/lib/Either'; +import { CreateRuleExceptionListItemSchema, createRuleExceptionListItemSchema } from '.'; +import { CreateExceptionListItemSchema } from '../create_exception_list_item_schema'; + +const getCreateExceptionListItemSchemaMock = (): CreateExceptionListItemSchema => ({ + comments: [], + description: 'some description', + entries: [ + { + field: 'host.name', + operator: 'included', + type: 'match_any', + value: ['foo', 'bar'], + }, + ], + item_id: undefined, + list_id: 'some-list-id', + name: 'some name', + namespace_type: 'single', + os_types: [], + tags: [], + type: 'simple', +}); + +describe('createRuleExceptionListItemSchema', () => { + test('empty objects do not validate', () => { + const payload = {} as CreateRuleExceptionListItemSchema; + + const decoded = createRuleExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + 'Invalid value "undefined" supplied to "entries"', + 'Invalid value "undefined" supplied to "name"', + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('items without list_id validate', () => { + const payload: CreateRuleExceptionListItemSchema = { + description: 'Exception item for rule default exception list', + entries: [ + { + field: 'some.not.nested.field', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + name: 'Sample exception item', + type: 'simple', + }; + + const decoded = createRuleExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual( + expect.objectContaining({ + comments: [], + description: 'Exception item for rule default exception list', + entries: [ + { + field: 'some.not.nested.field', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + name: 'Sample exception item', + os_types: [], + tags: [], + type: 'simple', + }) + ); + }); + + test('items with list_id do not validate', () => { + const payload = + getCreateExceptionListItemSchemaMock() as unknown as CreateRuleExceptionListItemSchema; + + const decoded = createRuleExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "some-list-id" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('made up parameters do not validate', () => { + const payload: Partial & { madeUp: string } = { + description: 'Exception item for rule default exception list', + entries: [ + { + field: 'some.not.nested.field', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + name: 'Sample exception item', + type: 'simple', + madeUp: 'invalid value', + }; + + const decoded = createRuleExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.ts new file mode 100644 index 0000000000000..ef0446d9207a7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/create_rule_exception_item_schema/index.ts @@ -0,0 +1,71 @@ +/* + * 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 * as t from 'io-ts'; +import { DefaultUuid } from '@kbn/securitysolution-io-ts-types'; + +import { + CreateCommentsArray, + DefaultCreateCommentsArray, + description, + EntriesArray, + exceptionListItemType, + ItemId, + meta, + NamespaceType, + namespaceType, + nonEmptyEntriesArray, + OsTypeArray, + osTypeArrayOrUndefined, + Tags, + tags, + name, + ExpireTimeOrUndefined, + expireTimeOrUndefined, +} from '../../common'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; + +export const createRuleExceptionListItemSchema = t.intersection([ + t.exact( + t.type({ + description, + entries: nonEmptyEntriesArray, + name, + type: exceptionListItemType, + }) + ), + t.exact( + t.partial({ + comments: DefaultCreateCommentsArray, // defaults to empty array if not set during decode + item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode + list_id: t.undefined, + meta, // defaults to undefined if not set during decode + namespace_type: namespaceType, // defaults to 'single' if not set during decode + os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode + tags, // defaults to empty array if not set during decode + expire_time: expireTimeOrUndefined, + }) + ), +]); + +export type CreateRuleExceptionListItemSchema = t.OutputOf< + typeof createRuleExceptionListItemSchema +>; + +// This type is used after a decode since some things are defaults after a decode. +export type CreateRuleExceptionListItemSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments' | 'expire_time' +> & { + comments: CreateCommentsArray; + tags: Tags; + item_id: ItemId; + entries: EntriesArray; + namespace_type: NamespaceType; + os_types: OsTypeArray; + expire_time: ExpireTimeOrUndefined; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..2547180e114f7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ID } from '../../constants/index.mock'; + +import { DeleteEndpointListItemSchema } from '.'; + +export const getDeleteEndpointListItemSchemaMock = (): DeleteEndpointListItemSchema => ({ + id: ID, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..09697db0c5f42 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.test.ts @@ -0,0 +1,49 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { DeleteEndpointListItemSchema, deleteEndpointListItemSchema } from '.'; +import { getDeleteEndpointListItemSchemaMock } from './index.mock'; + +describe('delete_endpoint_list_item_schema', () => { + test('it should validate a typical endpoint list item request', () => { + const payload = getDeleteEndpointListItemSchemaMock(); + const decoded = deleteEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept a value for "namespace_type" since it does not require one', () => { + const payload: DeleteEndpointListItemSchema & { + namespace_type: string; + } = { ...getDeleteEndpointListItemSchemaMock(), namespace_type: 'single' }; + // @ts-expect-error + delete payload.namespace_type; + const decoded = deleteEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getDeleteEndpointListItemSchemaMock()); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: DeleteEndpointListItemSchema & { + extraKey?: string; + } = { ...getDeleteEndpointListItemSchemaMock(), extraKey: 'some new value' }; + const decoded = deleteEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.ts new file mode 100644 index 0000000000000..9825b74142382 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_endpoint_list_item_schema/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; + +import { id } from '../../common/id'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { item_id } from '../../common/item_id'; + +export const deleteEndpointListItemSchema = t.exact( + t.partial({ + id, + item_id, + }) +); + +export type DeleteEndpointListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type DeleteEndpointListItemSchemaDecoded = RequiredKeepUndefined< + t.TypeOf +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..98404e189beb7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ID, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { DeleteExceptionListItemSchema } from '.'; + +export const getDeleteExceptionListItemSchemaMock = (): DeleteExceptionListItemSchema => ({ + id: ID, + namespace_type: NAMESPACE_TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..7131a969a795b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.test.ts @@ -0,0 +1,47 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { DeleteExceptionListItemSchema, deleteExceptionListItemSchema } from '.'; +import { getDeleteExceptionListItemSchemaMock } from './index.mock'; + +describe('delete_exception_list_item_schema', () => { + test('it should validate a typical exception list item request', () => { + const payload = getDeleteExceptionListItemSchemaMock(); + const decoded = deleteExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "namespace_type" but default to "single"', () => { + const payload = getDeleteExceptionListItemSchemaMock(); + delete payload.namespace_type; + const decoded = deleteExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getDeleteExceptionListItemSchemaMock()); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: DeleteExceptionListItemSchema & { + extraKey?: string; + } = getDeleteExceptionListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = deleteExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.ts new file mode 100644 index 0000000000000..02bcd800712ea --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_item_schema/index.ts @@ -0,0 +1,32 @@ +/* + * 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 * as t from 'io-ts'; + +import { NamespaceType } from '../../common/default_namespace'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { item_id } from '../../common/item_id'; +import { namespace_type } from '../../common/namespace_type'; + +export const deleteExceptionListItemSchema = t.exact( + t.partial({ + id, + item_id, + namespace_type, // defaults to 'single' if not set during decode + }) +); + +export type DeleteExceptionListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type DeleteExceptionListItemSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..7eca83a9d7135 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ID, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { DeleteExceptionListSchema } from '.'; + +export const getDeleteExceptionListSchemaMock = (): DeleteExceptionListSchema => ({ + id: ID, + namespace_type: NAMESPACE_TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..a439ac0403225 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.test.ts @@ -0,0 +1,47 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { DeleteExceptionListSchema, deleteExceptionListSchema } from '.'; +import { getDeleteExceptionListSchemaMock } from './index.mock'; + +describe('delete_exception_list_schema', () => { + test('it should validate a typical exception list request', () => { + const payload = getDeleteExceptionListSchemaMock(); + const decoded = deleteExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "namespace_type" but default to "single"', () => { + const payload = getDeleteExceptionListSchemaMock(); + delete payload.namespace_type; + const decoded = deleteExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getDeleteExceptionListSchemaMock()); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: DeleteExceptionListSchema & { + extraKey?: string; + } = getDeleteExceptionListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = deleteExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.ts new file mode 100644 index 0000000000000..1c04c0fdc17aa --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_exception_list_schema/index.ts @@ -0,0 +1,32 @@ +/* + * 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 * as t from 'io-ts'; + +import { NamespaceType } from '../../common/default_namespace'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { list_id } from '../../common/list_id'; +import { namespace_type } from '../../common/namespace_type'; + +export const deleteExceptionListSchema = t.exact( + t.partial({ + id, + list_id, + namespace_type, // defaults to 'single' if not set during decode + }) +); + +export type DeleteExceptionListSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type DeleteExceptionListSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..ef4ff721119a6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { ID, LIST_ID, VALUE } from '../../constants/index.mock'; + +import { DeleteListItemSchema } from '.'; + +export const getDeleteListItemSchemaMock = (): DeleteListItemSchema => ({ + id: ID, + list_id: LIST_ID, + value: VALUE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..07db295d3ef2d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.test.ts @@ -0,0 +1,36 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { DeleteListItemSchema, deleteListItemSchema } from '.'; +import { getDeleteListItemSchemaMock } from './index.mock'; + +describe('delete_list_item_schema', () => { + test('it should validate a typical list item request', () => { + const payload = getDeleteListItemSchemaMock(); + const decoded = deleteListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: DeleteListItemSchema & { + extraKey?: string; + } = { ...getDeleteListItemSchemaMock(), extraKey: 'some new value' }; + const decoded = deleteListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.ts new file mode 100644 index 0000000000000..4b9ef67630142 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_item_schema/index.ts @@ -0,0 +1,28 @@ +/* + * 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 * as t from 'io-ts'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { list_id } from '../../common/list_id'; +import { valueOrUndefined } from '../../common/value'; +import { refresh } from '../../common/refresh'; + +export const deleteListItemSchema = t.intersection([ + t.exact( + t.type({ + value: valueOrUndefined, + }) + ), + t.exact(t.partial({ id, list_id, refresh })), +]); + +export type DeleteListItemSchema = t.OutputOf; +export type DeleteListItemSchemaDecoded = RequiredKeepUndefined< + t.TypeOf +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.mock.ts new file mode 100644 index 0000000000000..19b7a2aa15b94 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { LIST_ID } from '../../constants/index.mock'; + +import { DeleteListSchema } from '.'; + +export const getDeleteListSchemaMock = (): DeleteListSchema => ({ + deleteReferences: false, + id: LIST_ID, + ignoreReferences: true, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.test.ts new file mode 100644 index 0000000000000..5077c0795df34 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.test.ts @@ -0,0 +1,46 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { DeleteListSchema, deleteListSchema } from '.'; +import { getDeleteListSchemaMock } from './index.mock'; + +describe('delete_list_schema', () => { + test('it should validate a typical lists request', () => { + const payload = getDeleteListSchemaMock(); + const decoded = deleteListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for an id', () => { + const payload = getDeleteListSchemaMock(); + // @ts-expect-error + delete payload.id; + const decoded = deleteListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: DeleteListSchema & { extraKey?: string } = getDeleteListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = deleteListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.ts new file mode 100644 index 0000000000000..da1d252d9e368 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/delete_list_schema/index.ts @@ -0,0 +1,29 @@ +/* + * 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 * as t from 'io-ts'; +import { DefaultStringBooleanFalse } from '@kbn/securitysolution-io-ts-types'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; + +export const deleteListSchema = t.intersection([ + t.exact( + t.type({ + id, + }) + ), + t.exact( + t.partial({ + deleteReferences: DefaultStringBooleanFalse, + ignoreReferences: DefaultStringBooleanFalse, + }) + ), +]); + +export type DeleteListSchema = RequiredKeepUndefined>; +export type DeleteListSchemaEncoded = t.OutputOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.mock.ts new file mode 100644 index 0000000000000..d3f9b59d5cf0e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { DuplicateExceptionListQuerySchema } from '.'; + +export const getDuplicateExceptionListQuerySchemaMock = (): DuplicateExceptionListQuerySchema => ({ + list_id: LIST_ID, + namespace_type: NAMESPACE_TYPE, + include_expired_exceptions: 'true', +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.test.ts new file mode 100644 index 0000000000000..73762793e3d2f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.test.ts @@ -0,0 +1,65 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { DuplicateExceptionListQuerySchema, duplicateExceptionListQuerySchema } from '.'; +import { getDuplicateExceptionListQuerySchemaMock } from './index.mock'; + +describe('duplicate_exceptionList_query_schema', () => { + test('it should validate a typical lists request', () => { + const payload = getDuplicateExceptionListQuerySchemaMock(); + const decoded = duplicateExceptionListQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should default namespace_type to "single" if an undefined given for namespacetype', () => { + const payload = getDuplicateExceptionListQuerySchemaMock(); + delete payload.namespace_type; + const decoded = duplicateExceptionListQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(message.schema).toEqual({ + include_expired_exceptions: 'true', + list_id: 'some-list-id', + namespace_type: 'single', + }); + }); + + test('it should NOT accept an undefined for an list_id', () => { + const payload = getDuplicateExceptionListQuerySchemaMock(); + // @ts-expect-error + delete payload.list_id; + const decoded = duplicateExceptionListQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: DuplicateExceptionListQuerySchema & { + extraKey?: string; + } = getDuplicateExceptionListQuerySchemaMock(); + payload.extraKey = 'some new value'; + const decoded = duplicateExceptionListQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.ts new file mode 100644 index 0000000000000..2a90eb4aeb05a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/duplicate_exception_list_query_schema/index.ts @@ -0,0 +1,33 @@ +/* + * 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 * as t from 'io-ts'; +import { NamespaceType } from '../../common'; + +import { includeExpiredExceptionsOrUndefined } from '../../common/include_expired_exceptions'; +import { list_id } from '../../common/list_id'; +import { namespace_type } from '../../common/namespace_type'; + +export const duplicateExceptionListQuerySchema = t.exact( + t.type({ + list_id, + namespace_type, + include_expired_exceptions: includeExpiredExceptionsOrUndefined, + }) +); + +export type DuplicateExceptionListQuerySchema = t.OutputOf< + typeof duplicateExceptionListQuerySchema +>; + +// This type is used after a decode since some things are defaults after a decode. +export type DuplicateExceptionListQuerySchemaDecoded = Omit< + t.TypeOf, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.mock.ts new file mode 100644 index 0000000000000..2b1d6a439064e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.mock.ts @@ -0,0 +1,17 @@ +/* + * 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 { ID, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { ExportExceptionListQuerySchema } from '.'; + +export const getExportExceptionListQuerySchemaMock = (): ExportExceptionListQuerySchema => ({ + id: ID, + list_id: LIST_ID, + namespace_type: NAMESPACE_TYPE, + include_expired_exceptions: 'true', +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.test.ts new file mode 100644 index 0000000000000..dea087dca36d8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.test.ts @@ -0,0 +1,78 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { ExportExceptionListQuerySchema, exportExceptionListQuerySchema } from '.'; +import { getExportExceptionListQuerySchemaMock } from './index.mock'; + +describe('export_exception_list_schema', () => { + test('it should validate a typical lists request', () => { + const payload = getExportExceptionListQuerySchemaMock(); + const decoded = exportExceptionListQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for an id', () => { + const payload = getExportExceptionListQuerySchemaMock(); + // @ts-expect-error + delete payload.id; + const decoded = exportExceptionListQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should default namespace_type to "single" if an undefined given for namespacetype', () => { + const payload = getExportExceptionListQuerySchemaMock(); + delete payload.namespace_type; + const decoded = exportExceptionListQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(message.schema).toEqual({ + id: 'uuid_here', + include_expired_exceptions: 'true', + list_id: 'some-list-id', + namespace_type: 'single', + }); + }); + + test('it should NOT accept an undefined for an list_id', () => { + const payload = getExportExceptionListQuerySchemaMock(); + // @ts-expect-error + delete payload.list_id; + const decoded = exportExceptionListQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ExportExceptionListQuerySchema & { + extraKey?: string; + } = getExportExceptionListQuerySchemaMock(); + payload.extraKey = 'some new value'; + const decoded = exportExceptionListQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.ts new file mode 100644 index 0000000000000..8967e45c5a61e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_exception_list_query_schema/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +import { id } from '../../common/id'; +import { includeExpiredExceptionsOrUndefined } from '../../common/include_expired_exceptions'; +import { list_id } from '../../common/list_id'; +import { namespace_type } from '../../common/namespace_type'; + +export const exportExceptionListQuerySchema = t.exact( + t.type({ + id, + list_id, + namespace_type, + include_expired_exceptions: includeExpiredExceptionsOrUndefined, + // TODO: Add file_name here with a default value + }) +); + +export type ExportExceptionListQuerySchema = t.OutputOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.mock.ts new file mode 100644 index 0000000000000..85076f592d16e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LIST_ID } from '../../constants/index.mock'; + +import { ExportListItemQuerySchema } from '.'; + +export const getExportListItemQuerySchemaMock = (): ExportListItemQuerySchema => ({ + list_id: LIST_ID, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.test.ts new file mode 100644 index 0000000000000..f05e530cbb415 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.test.ts @@ -0,0 +1,50 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { ExportListItemQuerySchema, exportListItemQuerySchema } from '.'; +import { getExportListItemQuerySchemaMock } from './index.mock'; + +describe('export_list_item_schema', () => { + test('it should validate a typical lists request', () => { + const payload = getExportListItemQuerySchemaMock(); + const decoded = exportListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for an id', () => { + const payload = getExportListItemQuerySchemaMock(); + // @ts-expect-error + delete payload.list_id; + const decoded = exportListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ExportListItemQuerySchema & { + extraKey?: string; + } = getExportListItemQuerySchemaMock(); + payload.extraKey = 'some new value'; + const decoded = exportListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.ts new file mode 100644 index 0000000000000..a07e6c73434e5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/export_list_item_query_schema/index.ts @@ -0,0 +1,23 @@ +/* + * 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 * as t from 'io-ts'; + +import { list_id } from '../../common/list_id'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; + +export const exportListItemQuerySchema = t.exact( + t.type({ + list_id, + // TODO: Add file_name here with a default value + }) +); + +export type ExportListItemQuerySchema = RequiredKeepUndefined< + t.TypeOf +>; +export type ExportListItemQuerySchemaEncoded = t.OutputOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..5df0322cc803f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.mock.ts @@ -0,0 +1,26 @@ +/* + * 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 { FILTER } from '../../constants/index.mock'; + +import { FindEndpointListItemSchema, FindEndpointListItemSchemaDecoded } from '.'; + +export const getFindEndpointListItemSchemaMock = (): FindEndpointListItemSchema => ({ + filter: FILTER, + page: '1', + per_page: '25', + sort_field: undefined, + sort_order: undefined, +}); + +export const getFindEndpointListItemSchemaDecodedMock = (): FindEndpointListItemSchemaDecoded => ({ + filter: FILTER, + page: 1, + per_page: 25, + sort_field: undefined, + sort_order: undefined, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..1ce9618781c46 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.test.ts @@ -0,0 +1,107 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { + getFindEndpointListItemSchemaDecodedMock, + getFindEndpointListItemSchemaMock, +} from './index.mock'; +import { FindEndpointListItemSchema, findEndpointListItemSchema } from '.'; + +describe('find_endpoint_list_item_schema', () => { + test('it should validate a typical find item request', () => { + const payload = getFindEndpointListItemSchemaMock(); + const decoded = findEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getFindEndpointListItemSchemaDecodedMock()); + }); + + test('it should validate and empty object since everything is optional and has defaults', () => { + const payload: FindEndpointListItemSchema = {}; + const decoded = findEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate with page missing', () => { + const payload = getFindEndpointListItemSchemaMock(); + delete payload.page; + const decoded = findEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindEndpointListItemSchemaDecodedMock(); + delete expected.page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with pre_page missing', () => { + const payload = getFindEndpointListItemSchemaMock(); + delete payload.per_page; + const decoded = findEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindEndpointListItemSchemaDecodedMock(); + delete expected.per_page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with filter missing', () => { + const payload = getFindEndpointListItemSchemaMock(); + delete payload.filter; + const decoded = findEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindEndpointListItemSchemaDecodedMock(); + delete expected.filter; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_field missing', () => { + const payload = getFindEndpointListItemSchemaMock(); + delete payload.sort_field; + const decoded = findEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindEndpointListItemSchemaDecodedMock(); + delete expected.sort_field; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_order missing', () => { + const payload = getFindEndpointListItemSchemaMock(); + delete payload.sort_order; + const decoded = findEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindEndpointListItemSchemaDecodedMock(); + delete expected.sort_order; + expect(message.schema).toEqual(expected); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: FindEndpointListItemSchema & { + extraKey: string; + } = { ...getFindEndpointListItemSchemaMock(), extraKey: 'some new value' }; + const decoded = findEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.ts new file mode 100644 index 0000000000000..05f32f452f5d9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_endpoint_list_item_schema/index.ts @@ -0,0 +1,31 @@ +/* + * 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 * as t from 'io-ts'; +import { StringToPositiveNumber } from '@kbn/securitysolution-io-ts-types'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { filter } from '../../common/filter'; +import { sort_field } from '../../common/sort_field'; +import { sort_order } from '../../common/sort_order'; + +export const findEndpointListItemSchema = t.exact( + t.partial({ + filter, // defaults to undefined if not set during decode + page: StringToPositiveNumber, // defaults to undefined if not set during decode + per_page: StringToPositiveNumber, // defaults to undefined if not set during decode + sort_field, // defaults to undefined if not set during decode + sort_order, // defaults to undefined if not set during decode + }) +); + +export type FindEndpointListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type FindEndpointListItemSchemaDecoded = RequiredKeepUndefined< + t.TypeOf +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..16b2ee7a8a370 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.mock.ts @@ -0,0 +1,56 @@ +/* + * 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 { FILTER, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { FindExceptionListItemSchema, FindExceptionListItemSchemaDecoded } from '.'; + +export const getFindExceptionListItemSchemaMock = (): FindExceptionListItemSchema => ({ + filter: FILTER, + list_id: LIST_ID, + namespace_type: NAMESPACE_TYPE, + page: '1', + per_page: '25', + search: undefined, + sort_field: undefined, + sort_order: undefined, +}); + +export const getFindExceptionListItemSchemaMultipleMock = (): FindExceptionListItemSchema => ({ + filter: 'name:Sofia Kovalevskaya,name:Hypatia,name:Sophie Germain', + list_id: 'list-1,list-2,list-3', + namespace_type: 'single,single,agnostic', + page: '1', + per_page: '25', + search: undefined, + sort_field: undefined, + sort_order: undefined, +}); + +export const getFindExceptionListItemSchemaDecodedMock = + (): FindExceptionListItemSchemaDecoded => ({ + filter: [FILTER], + list_id: [LIST_ID], + namespace_type: [NAMESPACE_TYPE], + page: 1, + per_page: 25, + search: undefined, + sort_field: undefined, + sort_order: undefined, + }); + +export const getFindExceptionListItemSchemaDecodedMultipleMock = + (): FindExceptionListItemSchemaDecoded => ({ + filter: ['name:Sofia Kovalevskaya', 'name:Hypatia', 'name:Sophie Germain'], + list_id: ['list-1', 'list-2', 'list-3'], + namespace_type: ['single', 'single', 'agnostic'], + page: 1, + per_page: 25, + search: undefined, + sort_field: undefined, + sort_order: undefined, + }); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..1d66969333212 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.test.ts @@ -0,0 +1,148 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { LIST_ID } from '../../constants/index.mock'; + +import { + getFindExceptionListItemSchemaDecodedMock, + getFindExceptionListItemSchemaDecodedMultipleMock, + getFindExceptionListItemSchemaMock, + getFindExceptionListItemSchemaMultipleMock, +} from './index.mock'; +import { + FindExceptionListItemSchema, + FindExceptionListItemSchemaDecoded, + findExceptionListItemSchema, +} from '.'; + +describe('find_list_item_schema', () => { + test('it should validate a typical find item request', () => { + const payload = getFindExceptionListItemSchemaMock(); + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getFindExceptionListItemSchemaDecodedMock()); + }); + + test('it should validate a typical find item request with multiple input strings turned into array elements', () => { + const payload = getFindExceptionListItemSchemaMultipleMock(); + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getFindExceptionListItemSchemaDecodedMultipleMock()); + }); + + test('it should validate just a list_id where it decodes into an array for list_id and adds a namespace_type of "single" as an array', () => { + const payload: FindExceptionListItemSchema = { list_id: LIST_ID }; + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected: FindExceptionListItemSchemaDecoded = { + filter: [], + list_id: [LIST_ID], + namespace_type: ['single'], + page: undefined, + per_page: undefined, + search: undefined, + sort_field: undefined, + sort_order: undefined, + }; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with page missing', () => { + const payload = getFindExceptionListItemSchemaMock(); + delete payload.page; + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListItemSchemaDecodedMock(); + delete expected.page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with per_page missing', () => { + const payload = getFindExceptionListItemSchemaMock(); + delete payload.per_page; + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListItemSchemaDecodedMock(); + delete expected.per_page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with filter missing and add filter as an empty array', () => { + const payload = getFindExceptionListItemSchemaMock(); + delete payload.filter; + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected: FindExceptionListItemSchemaDecoded = { + ...getFindExceptionListItemSchemaDecodedMock(), + filter: [], + }; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_field missing', () => { + const payload = getFindExceptionListItemSchemaMock(); + delete payload.sort_field; + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListItemSchemaDecodedMock(); + delete expected.sort_field; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_order missing', () => { + const payload = getFindExceptionListItemSchemaMock(); + delete payload.sort_order; + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListItemSchemaDecodedMock(); + delete expected.sort_order; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with search missing', () => { + const payload = getFindExceptionListItemSchemaMock(); + delete payload.search; + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListItemSchemaDecodedMock(); + delete expected.search; + expect(message.schema).toEqual(expected); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: FindExceptionListItemSchema & { + extraKey: string; + } = { ...getFindExceptionListItemSchemaMock(), extraKey: 'some new value' }; + const decoded = findExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.ts new file mode 100644 index 0000000000000..7177a7144c7fb --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_item_schema/index.ts @@ -0,0 +1,53 @@ +/* + * 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 * as t from 'io-ts'; +import { + EmptyStringArray, + EmptyStringArrayDecoded, + NonEmptyStringArray, + StringToPositiveNumber, +} from '@kbn/securitysolution-io-ts-types'; + +import { + DefaultNamespaceArray, + DefaultNamespaceArrayTypeDecoded, +} from '../../common/default_namespace_array'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { sort_field } from '../../common/sort_field'; +import { sort_order } from '../../common/sort_order'; +import { search } from '../../common/search'; + +export const findExceptionListItemSchema = t.intersection([ + t.exact( + t.type({ + list_id: NonEmptyStringArray, + }) + ), + t.exact( + t.partial({ + filter: EmptyStringArray, // defaults to an empty array [] if not set during decode + namespace_type: DefaultNamespaceArray, // defaults to ['single'] if not set during decode + page: StringToPositiveNumber, // defaults to undefined if not set during decode + per_page: StringToPositiveNumber, // defaults to undefined if not set during decode + search, + sort_field, // defaults to undefined if not set during decode + sort_order, // defaults to undefined if not set during decode + }) + ), +]); + +export type FindExceptionListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type FindExceptionListItemSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'namespace_type' | 'filter' +> & { + filter: EmptyStringArrayDecoded; + namespace_type: DefaultNamespaceArrayTypeDecoded; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..f963c6650cf29 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.mock.ts @@ -0,0 +1,28 @@ +/* + * 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 { FILTER, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { FindExceptionListSchema, FindExceptionListSchemaDecoded } from '.'; + +export const getFindExceptionListSchemaMock = (): FindExceptionListSchema => ({ + filter: FILTER, + namespace_type: NAMESPACE_TYPE, + page: '1', + per_page: '25', + sort_field: undefined, + sort_order: undefined, +}); + +export const getFindExceptionListSchemaDecodedMock = (): FindExceptionListSchemaDecoded => ({ + filter: FILTER, + namespace_type: [NAMESPACE_TYPE], + page: 1, + per_page: 25, + sort_field: undefined, + sort_order: undefined, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..8669a3657f025 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.test.ts @@ -0,0 +1,119 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { + getFindExceptionListSchemaDecodedMock, + getFindExceptionListSchemaMock, +} from './index.mock'; +import { + FindExceptionListSchema, + FindExceptionListSchemaDecoded, + findExceptionListSchema, +} from '.'; + +describe('find_exception_list_schema', () => { + test('it should validate a typical find item request', () => { + const payload = getFindExceptionListSchemaMock(); + const decoded = findExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getFindExceptionListSchemaDecodedMock()); + }); + + test('it should validate and empty object since everything is optional and will respond only with namespace_type filled out to be "single"', () => { + const payload: FindExceptionListSchema = {}; + const decoded = findExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected: FindExceptionListSchemaDecoded = { + filter: undefined, + namespace_type: ['single'], + page: undefined, + per_page: undefined, + sort_field: undefined, + sort_order: undefined, + }; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with page missing', () => { + const payload = getFindExceptionListSchemaMock(); + delete payload.page; + const decoded = findExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListSchemaDecodedMock(); + delete expected.page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with pre_page missing', () => { + const payload = getFindExceptionListSchemaMock(); + delete payload.per_page; + const decoded = findExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListSchemaDecodedMock(); + delete expected.per_page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with filter missing', () => { + const payload = getFindExceptionListSchemaMock(); + delete payload.filter; + const decoded = findExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListSchemaDecodedMock(); + delete expected.filter; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_field missing', () => { + const payload = getFindExceptionListSchemaMock(); + delete payload.sort_field; + const decoded = findExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListSchemaDecodedMock(); + delete expected.sort_field; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_order missing', () => { + const payload = getFindExceptionListSchemaMock(); + delete payload.sort_order; + const decoded = findExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindExceptionListSchemaDecodedMock(); + delete expected.sort_order; + expect(message.schema).toEqual(expected); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: FindExceptionListSchema & { + extraKey: string; + } = { ...getFindExceptionListSchemaMock(), extraKey: 'some new value' }; + const decoded = findExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.ts new file mode 100644 index 0000000000000..dc9acdefd7a97 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_exception_list_schema/index.ts @@ -0,0 +1,36 @@ +/* + * 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 * as t from 'io-ts'; +import { StringToPositiveNumber } from '@kbn/securitysolution-io-ts-types'; + +import { DefaultNamespaceArray, NamespaceTypeArray } from '../../common/default_namespace_array'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { filter } from '../../common/filter'; +import { sort_field } from '../../common/sort_field'; +import { sort_order } from '../../common/sort_order'; + +export const findExceptionListSchema = t.exact( + t.partial({ + filter, // defaults to undefined if not set during decode + namespace_type: DefaultNamespaceArray, // defaults to 'single' if not set during decode + page: StringToPositiveNumber, // defaults to undefined if not set during decode + per_page: StringToPositiveNumber, // defaults to undefined if not set during decode + sort_field, // defaults to undefined if not set during decode + sort_order, // defaults to undefined if not set during decode + }) +); + +export type FindExceptionListSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type FindExceptionListSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'namespace_type' +> & { + namespace_type: NamespaceTypeArray; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..44c952a9a3827 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.mock.ts @@ -0,0 +1,30 @@ +/* + * 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 { CURSOR, FILTER, LIST_ID } from '../../constants/index.mock'; + +import { FindListItemSchema, FindListItemSchemaDecoded } from '.'; + +export const getFindListItemSchemaMock = (): FindListItemSchema => ({ + cursor: CURSOR, + filter: FILTER, + list_id: LIST_ID, + page: '1', + per_page: '25', + sort_field: undefined, + sort_order: undefined, +}); + +export const getFindListItemSchemaDecodedMock = (): FindListItemSchemaDecoded => ({ + cursor: CURSOR, + filter: FILTER, + list_id: LIST_ID, + page: 1, + per_page: 25, + sort_field: undefined, + sort_order: undefined, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..589a40f641c67 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.test.ts @@ -0,0 +1,103 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { LIST_ID } from '../../constants/index.mock'; + +import { FindListItemSchema, FindListItemSchemaDecoded, findListItemSchema } from '.'; +import { getFindListItemSchemaDecodedMock, getFindListItemSchemaMock } from './index.mock'; + +describe('find_list_item_schema', () => { + test('it should validate a typical find item request', () => { + const payload = getFindListItemSchemaMock(); + const decoded = findListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getFindListItemSchemaDecodedMock()); + }); + + test('it should validate just a list_id where it decodes into an array for list_id and adds a namespace_type of "single"', () => { + const payload: FindListItemSchema = { list_id: LIST_ID }; + const decoded = findListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected: FindListItemSchemaDecoded = { + cursor: undefined, + filter: undefined, + list_id: LIST_ID, + page: undefined, + per_page: undefined, + sort_field: undefined, + sort_order: undefined, + }; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with page missing', () => { + const payload = getFindListItemSchemaMock(); + delete payload.page; + const decoded = findListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindListItemSchemaDecodedMock(); + delete expected.page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with pre_page missing', () => { + const payload = getFindListItemSchemaMock(); + delete payload.per_page; + const decoded = findListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindListItemSchemaDecodedMock(); + delete expected.per_page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_field missing', () => { + const payload = getFindListItemSchemaMock(); + delete payload.sort_field; + const decoded = findListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindListItemSchemaDecodedMock(); + delete expected.sort_field; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_order missing', () => { + const payload = getFindListItemSchemaMock(); + delete payload.sort_order; + const decoded = findListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindListItemSchemaDecodedMock(); + delete expected.sort_order; + expect(message.schema).toEqual(expected); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: FindListItemSchema & { + extraKey: string; + } = { ...getFindListItemSchemaMock(), extraKey: 'some new value' }; + const decoded = findListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.ts new file mode 100644 index 0000000000000..4279d5ef4a07f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_item_schema/index.ts @@ -0,0 +1,35 @@ +/* + * 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 * as t from 'io-ts'; + +import { StringToPositiveNumber } from '@kbn/securitysolution-io-ts-types'; +import { filter } from '../../common/filter'; +import { cursor } from '../../common/cursor'; +import { sort_field } from '../../common/sort_field'; +import { sort_order } from '../../common/sort_order'; +import { list_id } from '../../common/list_id'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; + +export const findListItemSchema = t.intersection([ + t.exact(t.type({ list_id })), + t.exact( + t.partial({ + cursor, // defaults to undefined if not set during decode + filter, // defaults to undefined if not set during decode + page: StringToPositiveNumber, // defaults to undefined if not set during decode + per_page: StringToPositiveNumber, // defaults to undefined if not set during decode + sort_field, // defaults to undefined if not set during decode + sort_order, // defaults to undefined if not set during decode + }) + ), +]); + +export type FindListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type FindListItemSchemaDecoded = RequiredKeepUndefined>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.mock.ts new file mode 100644 index 0000000000000..b80369fb6b432 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.mock.ts @@ -0,0 +1,27 @@ +/* + * 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 { FILTER } from '../../constants/index.mock'; + +import { FindListSchema, FindListSchemaEncoded } from '.'; + +export const getFindListSchemaMock = (): FindListSchemaEncoded => ({ + filter: FILTER, + page: '1', + per_page: '25', + sort_field: undefined, + sort_order: undefined, +}); + +export const getFindListSchemaDecodedMock = (): FindListSchema => ({ + cursor: undefined, + filter: FILTER, + page: 1, + per_page: 25, + sort_field: undefined, + sort_order: undefined, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.test.ts new file mode 100644 index 0000000000000..06b37bacf8452 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.test.ts @@ -0,0 +1,104 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getFindListSchemaDecodedMock, getFindListSchemaMock } from './index.mock'; +import { FindListSchemaEncoded, findListSchema } from '.'; + +describe('find_list_schema', () => { + test('it should validate a typical find item request', () => { + const payload = getFindListSchemaMock(); + const decoded = findListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getFindListSchemaDecodedMock()); + }); + + test('it should validate and empty object since everything is optional and will respond with an empty object', () => { + const payload: FindListSchemaEncoded = {}; + const decoded = findListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should validate with page missing', () => { + const payload = getFindListSchemaMock(); + delete payload.page; + const decoded = findListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindListSchemaDecodedMock(); + delete expected.page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with pre_page missing', () => { + const payload = getFindListSchemaMock(); + delete payload.per_page; + const decoded = findListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindListSchemaDecodedMock(); + delete expected.per_page; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with filter missing', () => { + const payload = getFindListSchemaMock(); + delete payload.filter; + const decoded = findListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindListSchemaDecodedMock(); + delete expected.filter; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_field missing', () => { + const payload = getFindListSchemaMock(); + delete payload.sort_field; + const decoded = findListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindListSchemaDecodedMock(); + delete expected.sort_field; + expect(message.schema).toEqual(expected); + }); + + test('it should validate with sort_order missing', () => { + const payload = getFindListSchemaMock(); + delete payload.sort_order; + const decoded = findListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + const expected = getFindListSchemaDecodedMock(); + delete expected.sort_order; + expect(message.schema).toEqual(expected); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: FindListSchemaEncoded & { + extraKey: string; + } = { ...getFindListSchemaMock(), extraKey: 'some new value' }; + const decoded = findListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.ts new file mode 100644 index 0000000000000..8f1520d0caf13 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/find_list_schema/index.ts @@ -0,0 +1,29 @@ +/* + * 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 * as t from 'io-ts'; + +import { StringToPositiveNumber } from '@kbn/securitysolution-io-ts-types'; +import { cursor } from '../../common/cursor'; +import { filter } from '../../common/filter'; +import { sort_field } from '../../common/sort_field'; +import { sort_order } from '../../common/sort_order'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; + +export const findListSchema = t.exact( + t.partial({ + cursor, // defaults to undefined if not set during decode + filter, // defaults to undefined if not set during decode + page: StringToPositiveNumber, // defaults to undefined if not set during decode + per_page: StringToPositiveNumber, // defaults to undefined if not set during decode + sort_field, // defaults to undefined if not set during decode + sort_order, // defaults to undefined if not set during decode + }) +); + +export type FindListSchema = RequiredKeepUndefined>; +export type FindListSchemaEncoded = t.OutputOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/get_exception_filter_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/get_exception_filter_schema/index.ts new file mode 100644 index 0000000000000..656d6cea6164e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/get_exception_filter_schema/index.ts @@ -0,0 +1,38 @@ +/* + * 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 * as t from 'io-ts'; +import { namespaceType } from '../../common/default_namespace'; +import { exceptionListItemSchema } from '../../response'; +import { createExceptionListItemSchema } from '../create_exception_list_item_schema'; + +const exceptionListId = t.type({ + exception_list_id: t.string, + namespace_type: namespaceType, +}); + +export const exceptionListIds = t.type({ + exception_list_ids: t.array(exceptionListId), + type: t.literal('exception_list_ids'), +}); + +export const exceptions = t.type({ + exceptions: t.array(t.union([exceptionListItemSchema, createExceptionListItemSchema])), + type: t.literal('exception_items'), +}); + +const optionalExceptionParams = t.exact( + t.partial({ alias: t.string, chunk_size: t.number, exclude_exceptions: t.boolean }) +); + +export const getExceptionFilterSchema = t.intersection([ + t.union([exceptions, exceptionListIds]), + optionalExceptionParams, +]); + +export type GetExceptionFilterSchema = t.TypeOf; +export type ExceptionListId = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.mock.ts new file mode 100644 index 0000000000000..a50c455a9d60f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.mock.ts @@ -0,0 +1,34 @@ +/* + * 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 { ENTRIES } from '../../constants/index.mock'; +import { ImportExceptionListItemSchema, ImportExceptionListItemSchemaDecoded } from '.'; + +export const getImportExceptionsListItemSchemaMock = ( + itemId = 'item_id_1', + listId = 'detection_list_id' +): ImportExceptionListItemSchema => ({ + description: 'some description', + entries: ENTRIES, + item_id: itemId, + list_id: listId, + name: 'Query with a rule id', + type: 'simple', +}); + +export const getImportExceptionsListItemSchemaDecodedMock = ( + itemId = 'item_id_1', + listId = 'detection_list_id' +): ImportExceptionListItemSchemaDecoded => ({ + ...getImportExceptionsListItemSchemaMock(itemId, listId), + comments: [], + meta: undefined, + namespace_type: 'single', + os_types: [], + tags: [], + expire_time: undefined, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.test.ts new file mode 100644 index 0000000000000..61e135bfd59a6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.test.ts @@ -0,0 +1,172 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { importExceptionListItemSchema, ImportExceptionListItemSchema } from '.'; +import { + getImportExceptionsListItemSchemaDecodedMock, + getImportExceptionsListItemSchemaMock, +} from './index.mock'; +import { getCommentsArrayMock } from '../../common/comment/index.mock'; + +describe('import_list_item_schema', () => { + test('it should validate a typical item request', () => { + const payload = getImportExceptionsListItemSchemaMock(); + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getImportExceptionsListItemSchemaDecodedMock()); + }); + + test('it should validate a typical item request with comments', () => { + const payload = { + ...getImportExceptionsListItemSchemaMock(), + comments: getCommentsArrayMock(), + }; + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual({ + ...getImportExceptionsListItemSchemaDecodedMock(), + comments: [ + { + comment: 'some old comment', + created_at: '2020-04-20T15:25:31.830Z', + created_by: 'some user', + id: 'uuid_here', + }, + { + comment: 'some old comment', + created_at: '2020-04-20T15:25:31.830Z', + created_by: 'some user', + id: 'uuid_here', + }, + ], + }); + }); + + test('it should NOT accept an undefined for "item_id"', () => { + const payload: Partial> = + getImportExceptionsListItemSchemaMock(); + delete payload.item_id; + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "item_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "list_id"', () => { + const payload: Partial> = + getImportExceptionsListItemSchemaMock(); + delete payload.list_id; + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "description"', () => { + const payload: Partial> = + getImportExceptionsListItemSchemaMock(); + delete payload.description; + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "name"', () => { + const payload: Partial> = + getImportExceptionsListItemSchemaMock(); + delete payload.name; + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "type"', () => { + const payload: Partial> = + getImportExceptionsListItemSchemaMock(); + delete payload.type; + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "entries"', () => { + const payload: Partial> = + getImportExceptionsListItemSchemaMock(); + delete payload.entries; + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept any partial fields', () => { + const payload: ImportExceptionListItemSchema = { + ...getImportExceptionsListItemSchemaMock(), + id: '123', + namespace_type: 'single', + comments: [], + os_types: [], + tags: ['123'], + created_at: '2018-08-24T17:49:30.145142000', + created_by: 'elastic', + updated_at: '2018-08-24T17:49:30.145142000', + updated_by: 'elastic', + tie_breaker_id: '123', + _version: '3', + meta: undefined, + }; + + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ImportExceptionListItemSchema & { + extraKey?: string; + } = getImportExceptionsListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = importExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.ts new file mode 100644 index 0000000000000..a2d60e292aff5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_item_schema/index.ts @@ -0,0 +1,86 @@ +/* + * 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 * as t from 'io-ts'; + +import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; +import { Tags, tags } from '../../common/tags'; +import { NamespaceType } from '../../common/default_namespace'; +import { name } from '../../common/name'; +import { description } from '../../common/description'; +import { namespace_type } from '../../common/namespace_type'; +import { meta } from '../../common/meta'; +import { list_id } from '../../common/list_id'; +import { item_id, ItemId } from '../../common/item_id'; +import { id } from '../../common/id'; +import { created_at } from '../../common/created_at'; +import { created_by } from '../../common/created_by'; +import { updated_at } from '../../common/updated_at'; +import { updated_by } from '../../common/updated_by'; +import { _version } from '../../common/underscore_version'; +import { tie_breaker_id } from '../../common/tie_breaker_id'; +import { nonEmptyEntriesArray } from '../../common/non_empty_entries_array'; +import { exceptionListItemType } from '../../common/exception_list_item_type'; +import { EntriesArray } from '../../common/entries'; +import { DefaultImportCommentsArray } from '../../common/default_import_comments_array'; +import { ExpireTimeOrUndefined, expireTimeOrUndefined, ImportCommentsArray } from '../../common'; + +/** + * Differences from this and the createExceptionsListItemSchema are + * - item_id is required + * - id is optional (but ignored in the import code - item_id is exclusively used for imports) + * - immutable is optional but if it is any value other than false it will be rejected + * - created_at is optional (but ignored in the import code) + * - updated_at is optional (but ignored in the import code) + * - created_by is optional (but ignored in the import code) + * - updated_by is optional (but ignored in the import code) + */ +export const importExceptionListItemSchema = t.intersection([ + t.exact( + t.type({ + description, + entries: nonEmptyEntriesArray, + item_id, + list_id, + name, + type: exceptionListItemType, + }) + ), + t.exact( + t.partial({ + id, // defaults to undefined if not set during decode + comments: DefaultImportCommentsArray, // defaults to empty array if not set during decode + created_at, // defaults undefined if not set during decode + updated_at, // defaults undefined if not set during decode + created_by, // defaults undefined if not set during decode + updated_by, // defaults undefined if not set during decode + _version, // defaults to undefined if not set during decode + tie_breaker_id, + meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode + os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode + tags, // defaults to empty array if not set during decode + expire_time: expireTimeOrUndefined, + }) + ), +]); + +export type ImportExceptionListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type ImportExceptionListItemSchemaDecoded = Omit< + ImportExceptionListItemSchema, + 'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments' | 'expire_time' +> & { + comments: ImportCommentsArray; + tags: Tags; + item_id: ItemId; + entries: EntriesArray; + namespace_type: NamespaceType; + os_types: OsTypeArray; + expire_time: ExpireTimeOrUndefined; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..438b0cd54fb09 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.mock.ts @@ -0,0 +1,29 @@ +/* + * 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 { ImportExceptionListSchemaDecoded, ImportExceptionsListSchema } from '.'; + +export const getImportExceptionsListSchemaMock = ( + listId = 'detection_list_id' +): ImportExceptionsListSchema => ({ + description: 'some description', + list_id: listId, + name: 'Query with a rule id', + type: 'detection', +}); + +export const getImportExceptionsListSchemaDecodedMock = ( + listId = 'detection_list_id' +): ImportExceptionListSchemaDecoded => ({ + ...getImportExceptionsListSchemaMock(listId), + immutable: false, + meta: undefined, + namespace_type: 'single', + os_types: [], + tags: [], + version: 1, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..e1d0a55a17704 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.test.ts @@ -0,0 +1,131 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { importExceptionsListSchema, ImportExceptionsListSchema } from '.'; +import { + getImportExceptionsListSchemaMock, + getImportExceptionsListSchemaDecodedMock, +} from './index.mock'; + +describe('import_list_item_schema', () => { + test('it should validate a typical lists request', () => { + const payload = getImportExceptionsListSchemaMock(); + const decoded = importExceptionsListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getImportExceptionsListSchemaDecodedMock()); + }); + + test('it should NOT accept an undefined for "list_id"', () => { + const payload: Partial> = + getImportExceptionsListSchemaMock(); + delete payload.list_id; + const decoded = importExceptionsListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "description"', () => { + const payload: Partial> = + getImportExceptionsListSchemaMock(); + delete payload.description; + const decoded = importExceptionsListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "name"', () => { + const payload: Partial> = + getImportExceptionsListSchemaMock(); + delete payload.name; + const decoded = importExceptionsListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "type"', () => { + const payload: Partial> = + getImportExceptionsListSchemaMock(); + delete payload.type; + const decoded = importExceptionsListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept value of "true" for "immutable"', () => { + const payload: ImportExceptionsListSchema = { + ...getImportExceptionsListSchemaMock(), + immutable: true, + }; + + const decoded = importExceptionsListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "true" supplied to "immutable"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept any partial fields', () => { + const payload: ImportExceptionsListSchema = { + ...getImportExceptionsListSchemaMock(), + namespace_type: 'single', + immutable: false, + os_types: [], + tags: ['123'], + created_at: '2018-08-24T17:49:30.145142000', + created_by: 'elastic', + updated_at: '2018-08-24T17:49:30.145142000', + updated_by: 'elastic', + version: 3, + tie_breaker_id: '123', + _version: '3', + meta: undefined, + }; + + const decoded = importExceptionsListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ImportExceptionsListSchema & { + extraKey?: string; + } = getImportExceptionsListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = importExceptionsListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.ts new file mode 100644 index 0000000000000..98f5988daf1cc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_exception_list_schema/index.ts @@ -0,0 +1,84 @@ +/* + * 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 * as t from 'io-ts'; + +import { + DefaultVersionNumber, + DefaultVersionNumberDecoded, + OnlyFalseAllowed, +} from '@kbn/securitysolution-io-ts-types'; + +import { exceptionListType } from '../../common/exception_list'; +import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; +import { Tags, tags } from '../../common/tags'; +import { ListId, list_id } from '../../common/list_id'; +import { NamespaceType } from '../../common/default_namespace'; +import { name } from '../../common/name'; +import { description } from '../../common/description'; +import { namespace_type } from '../../common/namespace_type'; +import { meta } from '../../common/meta'; +import { id } from '../../common/id'; +import { created_at } from '../../common/created_at'; +import { created_by } from '../../common/created_by'; +import { updated_at } from '../../common/updated_at'; +import { updated_by } from '../../common/updated_by'; +import { _version } from '../../common/underscore_version'; +import { tie_breaker_id } from '../../common/tie_breaker_id'; + +/** + * Differences from this and the createExceptionsSchema are + * - list_id is required + * - id is optional (but ignored in the import code - list_id is exclusively used for imports) + * - immutable is optional but if it is any value other than false it will be rejected + * - created_at is optional (but ignored in the import code) + * - updated_at is optional (but ignored in the import code) + * - created_by is optional (but ignored in the import code) + * - updated_by is optional (but ignored in the import code) + */ +export const importExceptionsListSchema = t.intersection([ + t.exact( + t.type({ + description, + name, + type: exceptionListType, + list_id, + }) + ), + t.exact( + t.partial({ + id, // defaults to undefined if not set during decode + immutable: OnlyFalseAllowed, + meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode + os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode + tags, // defaults to empty array if not set during decode + created_at, // defaults "undefined" if not set during decode + updated_at, // defaults "undefined" if not set during decode + created_by, // defaults "undefined" if not set during decode + updated_by, // defaults "undefined" if not set during decode + _version, // defaults to undefined if not set during decode + tie_breaker_id, + version: DefaultVersionNumber, // defaults to numerical 1 if not set during decode + }) + ), +]); + +export type ImportExceptionsListSchema = t.TypeOf; + +// This type is used after a decode since some things are defaults after a decode. +export type ImportExceptionListSchemaDecoded = Omit< + ImportExceptionsListSchema, + 'tags' | 'list_id' | 'namespace_type' | 'os_types' | 'immutable' +> & { + immutable: false; + tags: Tags; + list_id: ListId; + namespace_type: NamespaceType; + os_types: OsTypeArray; + version: DefaultVersionNumberDecoded; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.mock.ts new file mode 100644 index 0000000000000..fc5fc0ca703b0 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.mock.ts @@ -0,0 +1,18 @@ +/* + * 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 { LIST_ID, TYPE } from '../../constants/index.mock'; + +import { ImportListItemQuerySchema } from '.'; + +export const getImportListItemQuerySchemaMock = (): ImportListItemQuerySchema => ({ + deserializer: undefined, + list_id: LIST_ID, + serializer: undefined, + type: TYPE, + refresh: 'false', +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.test.ts new file mode 100644 index 0000000000000..26d1ba486468f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.test.ts @@ -0,0 +1,88 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { ImportListItemQuerySchema, importListItemQuerySchema } from '.'; +import { getImportListItemQuerySchemaMock } from './index.mock'; + +describe('import_list_item_schema', () => { + test('it should validate a typical lists request', () => { + const payload = getImportListItemQuerySchemaMock(); + const decoded = importListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "list_id"', () => { + const payload = getImportListItemQuerySchemaMock(); + delete payload.list_id; + const decoded = importListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "type"', () => { + const payload = getImportListItemQuerySchemaMock(); + delete payload.type; + const decoded = importListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "type" and "list_id', () => { + const payload = getImportListItemQuerySchemaMock(); + delete payload.type; + delete payload.list_id; + const decoded = importListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "serializer"', () => { + const payload = getImportListItemQuerySchemaMock(); + delete payload.serializer; + const decoded = importListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "deserializer"', () => { + const payload = getImportListItemQuerySchemaMock(); + delete payload.deserializer; + const decoded = importListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ImportListItemQuerySchema & { + extraKey?: string; + } = getImportListItemQuerySchemaMock(); + payload.extraKey = 'some new value'; + const decoded = importListItemQuerySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.ts new file mode 100644 index 0000000000000..19cd873825d2d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_query_schema/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { deserializer } from '../../common/deserializer'; +import { list_id } from '../../common/list_id'; +import { type } from '../../common/type'; +import { serializer } from '../../common/serializer'; +import { refreshWithWaitFor } from '../../common/refresh'; + +export const importListItemQuerySchema = t.exact( + t.partial({ deserializer, list_id, serializer, type, refresh: refreshWithWaitFor }) +); + +export type ImportListItemQuerySchema = RequiredKeepUndefined< + t.TypeOf +>; +export type ImportListItemQuerySchemaEncoded = t.OutputOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..32fee251c0781 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.mock.ts @@ -0,0 +1,21 @@ +/* + * 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 { ImportListItemSchema } from '.'; + +export const getImportListItemSchemaMock = (): ImportListItemSchema => ({ + file: {}, +}); + +/** + * This is useful for end to end tests, it will return a buffer given a string array + * of things to import. + * @param input Array of strings of things to import + */ +export const getImportListItemAsBuffer = (input: string[]): Buffer => { + return Buffer.from(input.join('\r\n')); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..0e572255b5741 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.test.ts @@ -0,0 +1,50 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { ImportListItemSchema, importListItemSchema } from '.'; +import { getImportListItemSchemaMock } from './index.mock'; + +describe('import_list_item_schema', () => { + test('it should validate a typical lists request', () => { + const payload = getImportListItemSchemaMock(); + const decoded = importListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for a file', () => { + const payload = getImportListItemSchemaMock(); + // @ts-expect-error + delete payload.file; + const decoded = importListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "file"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ImportListItemSchema & { + extraKey?: string; + } = getImportListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = importListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.ts new file mode 100644 index 0000000000000..4072cf029bae9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/import_list_item_schema/index.ts @@ -0,0 +1,20 @@ +/* + * 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 * as t from 'io-ts'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { file } from '../../common/file'; + +export const importListItemSchema = t.exact( + t.type({ + file, + }) +); + +export type ImportListItemSchema = RequiredKeepUndefined>; +export type ImportListItemSchemaEncoded = t.OutputOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts new file mode 100644 index 0000000000000..a6a3099ddde8c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/index.ts @@ -0,0 +1,47 @@ +/* + * 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. + */ + +export * from './create_endpoint_list_item_schema'; +export * from './create_exception_list_item_schema'; +export * from './create_exception_list_schema'; +export * from './create_rule_exception_item_schema'; +export * from './create_list_item_schema'; +export * from './create_list_schema'; +export * from './delete_endpoint_list_item_schema'; +export * from './delete_exception_list_schema'; +export * from './delete_exception_list_item_schema'; +export * from './delete_list_item_schema'; +export * from './delete_list_schema'; +export * from './duplicate_exception_list_query_schema'; +export * from './export_exception_list_query_schema'; +export * from './export_list_item_query_schema'; +export * from './find_endpoint_list_item_schema'; +export * from './find_exception_list_schema'; +export * from './find_exception_list_item_schema'; +export * from './find_list_item_schema'; +export * from './find_list_schema'; +export * from './get_exception_filter_schema'; +export * from './import_list_item_query_schema'; +export * from './import_exception_list_schema'; +export * from './import_exception_item_schema'; +export * from './import_list_item_schema'; +export * from './patch_list_item_schema'; +export * from './patch_list_schema'; +export * from './read_endpoint_list_item_schema'; +export * from './read_exception_list_item_schema'; +export * from './read_exception_list_schema'; +export * from './read_list_item_schema'; +export * from './read_list_schema'; +export * from './summary_exception_list_schema'; +export * from './update_endpoint_list_item_schema'; +export * from './update_exception_list_item_schema'; +export * from './update_exception_list_schema'; +export * from './update_list_item_schema'; +export * from './update_list_schema'; + +// Internal routes +export * from './internal/create_exception_list_schema'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..8ab58a7b0bdd4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.test.ts @@ -0,0 +1,68 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; + +import { ExceptionListTypeEnum } from '../../../common/exception_list'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { internalCreateExceptionListSchema } from '.'; +import { getCreateExceptionListSchemaMock } from '../../create_exception_list_schema/index.mock'; + +describe('create_exception_list_schema', () => { + test('it should accept artifact list_id', () => { + const payload = { + ...getCreateExceptionListSchemaMock(), + list_id: ExceptionListTypeEnum.ENDPOINT_BLOCKLISTS, + }; + const decoded = internalCreateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + test('it should fail when invalid list_id', () => { + const payload = { + ...getCreateExceptionListSchemaMock(), + list_id: ExceptionListTypeEnum.DETECTION, + }; + const decoded = internalCreateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "detection" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + test('it should accept artifact type', () => { + const payload = { + ...getCreateExceptionListSchemaMock(), + list_id: ExceptionListTypeEnum.ENDPOINT_BLOCKLISTS, + type: ExceptionListTypeEnum.ENDPOINT_BLOCKLISTS, + }; + const decoded = internalCreateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + test('it should fail when invalid type', () => { + const payload = { + ...getCreateExceptionListSchemaMock(), + list_id: ExceptionListTypeEnum.ENDPOINT_BLOCKLISTS, + type: ExceptionListTypeEnum.DETECTION, + }; + const decoded = internalCreateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "detection" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.ts new file mode 100644 index 0000000000000..ff8f9670a4e03 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/internal/create_exception_list_schema/index.ts @@ -0,0 +1,46 @@ +/* + * 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 { ENDPOINT_ARTIFACT_LIST_IDS } from '@kbn/securitysolution-list-constants'; +import * as t from 'io-ts'; + +import { + createExceptionListSchema, + CreateExceptionListSchemaDecoded, +} from '../../create_exception_list_schema'; + +export const internalCreateExceptionListSchema = t.intersection([ + t.exact( + t.type({ + type: t.keyof({ + endpoint: null, + endpoint_events: null, + endpoint_host_isolation_exceptions: null, + endpoint_blocklists: null, + }), + }) + ), + t.exact( + t.partial({ + list_id: t.keyof( + ENDPOINT_ARTIFACT_LIST_IDS.reduce>((mapOfListIds, listId) => { + mapOfListIds[listId] = null; + + return mapOfListIds; + }, {}) + ), + }) + ), + createExceptionListSchema, +]); + +export type InternalCreateExceptionListSchema = t.OutputOf< + typeof internalCreateExceptionListSchema +>; + +// This type is used after a decode since some things are defaults after a decode. +export type InternalCreateExceptionListSchemaDecoded = CreateExceptionListSchemaDecoded; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..fd30cba204398 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { LIST_ITEM_ID, META, VALUE } from '../../constants/index.mock'; + +import { PatchListItemSchema } from '.'; + +export const getPathListItemSchemaMock = (): PatchListItemSchema => ({ + id: LIST_ITEM_ID, + meta: META, + value: VALUE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..55050ea6eab86 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.test.ts @@ -0,0 +1,81 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getPathListItemSchemaMock } from './index.mock'; +import { PatchListItemSchema, patchListItemSchema } from '.'; + +describe('patch_list_item_schema', () => { + test('it should validate a typical list item request', () => { + const payload = getPathListItemSchemaMock(); + const decoded = patchListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "id"', () => { + const payload = getPathListItemSchemaMock(); + // @ts-expect-error + delete payload.id; + const decoded = patchListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "meta"', () => { + const payload = getPathListItemSchemaMock(); + delete payload.meta; + const decoded = patchListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "value"', () => { + const payload = getPathListItemSchemaMock(); + delete payload.value; + const decoded = patchListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "meta" and "value"', () => { + const payload = getPathListItemSchemaMock(); + delete payload.meta; + delete payload.value; + const decoded = patchListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: PatchListItemSchema & { extraKey?: string } = getPathListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = patchListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.ts new file mode 100644 index 0000000000000..caa0d62f003f1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_item_schema/index.ts @@ -0,0 +1,29 @@ +/* + * 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 * as t from 'io-ts'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { _version } from '../../common/underscore_version'; +import { id } from '../../common/id'; +import { meta } from '../../common/meta'; +import { value } from '../../common/value'; +import { refresh } from '../../common/refresh'; + +export const patchListItemSchema = t.intersection([ + t.exact( + t.type({ + id, + }) + ), + t.exact(t.partial({ _version, meta, value, refresh })), +]); + +export type PatchListItemSchema = t.OutputOf; +export type PatchListItemSchemaDecoded = RequiredKeepUndefined< + t.TypeOf +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.mock.ts new file mode 100644 index 0000000000000..2b71a46c46659 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.mock.ts @@ -0,0 +1,17 @@ +/* + * 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 { DESCRIPTION, LIST_ITEM_ID, META, NAME } from '../../constants/index.mock'; + +import { PatchListSchema } from '.'; + +export const getPathListSchemaMock = (): PatchListSchema => ({ + description: DESCRIPTION, + id: LIST_ITEM_ID, + meta: META, + name: NAME, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.test.ts new file mode 100644 index 0000000000000..be0dd3b2f6eaa --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.test.ts @@ -0,0 +1,129 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getPathListSchemaMock } from './index.mock'; +import { PatchListSchema, patchListSchema } from '.'; + +describe('patch_list_schema', () => { + test('it should validate a typical list item request', () => { + const payload = getPathListSchemaMock(); + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "id"', () => { + const payload = getPathListSchemaMock(); + // @ts-expect-error + delete payload.id; + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "meta"', () => { + const payload = getPathListSchemaMock(); + delete payload.meta; + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "name"', () => { + const payload = getPathListSchemaMock(); + delete payload.name; + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "description"', () => { + const payload = getPathListSchemaMock(); + delete payload.description; + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "description", "meta", "name', () => { + const payload = getPathListSchemaMock(); + delete payload.description; + delete payload.name; + delete payload.meta; + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "description", "meta"', () => { + const payload = getPathListSchemaMock(); + delete payload.description; + delete payload.meta; + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "description", "name"', () => { + const payload = getPathListSchemaMock(); + delete payload.description; + delete payload.name; + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "meta", "name"', () => { + const payload = getPathListSchemaMock(); + delete payload.meta; + delete payload.name; + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: PatchListSchema & { extraKey?: string } = getPathListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = patchListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.ts new file mode 100644 index 0000000000000..cb72d902f1896 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/patch_list_schema/index.ts @@ -0,0 +1,36 @@ +/* + * 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 * as t from 'io-ts'; +import { version } from '@kbn/securitysolution-io-ts-types'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { _version } from '../../common/underscore_version'; +import { meta } from '../../common/meta'; +import { name } from '../../common/name'; +import { description } from '../../common/description'; + +export const patchListSchema = t.intersection([ + t.exact( + t.type({ + id, + }) + ), + t.exact( + t.partial({ + _version, // is undefined if not set during decode + description, // is undefined if not set during decode + meta, // is undefined if not set during decode + name, // is undefined if not set during decode + version, // is undefined if not set during decode + }) + ), +]); + +export type PatchListSchema = t.OutputOf; +export type PatchListSchemaDecoded = RequiredKeepUndefined>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..7b83368ad73e4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ID, ITEM_ID } from '../../constants/index.mock'; + +import { ReadEndpointListItemSchema } from '.'; + +export const getReadEndpointListItemSchemaMock = (): ReadEndpointListItemSchema => ({ + id: ID, + item_id: ITEM_ID, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..dc8a14b2ef101 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.test.ts @@ -0,0 +1,85 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getReadEndpointListItemSchemaMock } from './index.mock'; +import { ReadEndpointListItemSchema, readEndpointListItemSchema } from '.'; + +describe('read_endpoint_list_item_schema', () => { + test('it should validate a typical list request', () => { + const payload = getReadEndpointListItemSchemaMock(); + const decoded = readEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id"', () => { + const payload = getReadEndpointListItemSchemaMock(); + delete payload.id; + const decoded = readEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "item_id"', () => { + const payload = getReadEndpointListItemSchemaMock(); + delete payload.item_id; + const decoded = readEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept "namespace_type" since endpoint list items do not need it', () => { + const payload: ReadEndpointListItemSchema & { + namespace_type: string; + } = { ...getReadEndpointListItemSchemaMock(), namespace_type: 'single' }; + // @ts-expect-error + delete payload.namespace_type; + const decoded = readEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getReadEndpointListItemSchemaMock()); + }); + + test('it should accept an undefined for "id", "item_id"', () => { + const payload = getReadEndpointListItemSchemaMock(); + delete payload.id; + delete payload.item_id; + const decoded = readEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ReadEndpointListItemSchema & { + extraKey?: string; + } = getReadEndpointListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = readEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.ts new file mode 100644 index 0000000000000..6e32b1fe5186c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_endpoint_list_item_schema/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { item_id } from '../../common/item_id'; + +export const readEndpointListItemSchema = t.exact( + t.partial({ + id, + item_id, + }) +); + +export type ReadEndpointListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type ReadEndpointListItemSchemaDecoded = RequiredKeepUndefined< + t.TypeOf +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..6ce6e68ec6e0a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { ID, ITEM_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { ReadExceptionListItemSchema } from '.'; + +export const getReadExceptionListItemSchemaMock = (): ReadExceptionListItemSchema => ({ + id: ID, + item_id: ITEM_ID, + namespace_type: NAMESPACE_TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..68f636ccb8705 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.test.ts @@ -0,0 +1,126 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getReadExceptionListItemSchemaMock } from './index.mock'; +import { ReadExceptionListItemSchema, readExceptionListItemSchema } from '.'; + +describe('read_exception_list_item_schema', () => { + test('it should validate a typical exception list request', () => { + const payload = getReadExceptionListItemSchemaMock(); + const decoded = readExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id"', () => { + const payload = getReadExceptionListItemSchemaMock(); + delete payload.id; + const decoded = readExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "item_id"', () => { + const payload = getReadExceptionListItemSchemaMock(); + delete payload.item_id; + const decoded = readExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "namespace_type" but default to "single"', () => { + const payload = getReadExceptionListItemSchemaMock(); + delete payload.namespace_type; + const decoded = readExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getReadExceptionListItemSchemaMock()); + }); + + test('it should accept an undefined for "id", "item_id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getReadExceptionListItemSchemaMock(); + delete payload.id; + delete payload.namespace_type; + delete payload.item_id; + const output = getReadExceptionListItemSchemaMock(); + delete output.id; + delete output.item_id; + const decoded = readExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should accept an undefined for "id", "item_id"', () => { + const payload = getReadExceptionListItemSchemaMock(); + delete payload.id; + delete payload.item_id; + const decoded = readExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getReadExceptionListItemSchemaMock(); + delete payload.id; + delete payload.namespace_type; + const output = getReadExceptionListItemSchemaMock(); + delete output.id; + const decoded = readExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should accept an undefined for "item_id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getReadExceptionListItemSchemaMock(); + delete payload.namespace_type; + delete payload.item_id; + const output = getReadExceptionListItemSchemaMock(); + delete output.item_id; + const decoded = readExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ReadExceptionListItemSchema & { + extraKey?: string; + } = getReadExceptionListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = readExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.ts new file mode 100644 index 0000000000000..9111587af7e93 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_item_schema/index.ts @@ -0,0 +1,32 @@ +/* + * 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 * as t from 'io-ts'; + +import { NamespaceType } from '../../common/default_namespace'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { item_id } from '../../common/item_id'; +import { namespace_type } from '../../common/namespace_type'; + +export const readExceptionListItemSchema = t.exact( + t.partial({ + id, + item_id, + namespace_type, // defaults to 'single' if not set during decode + }) +); + +export type ReadExceptionListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type ReadExceptionListItemSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..f122f1d20339e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { ID, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { ReadExceptionListSchema } from '.'; + +export const getReadExceptionListSchemaMock = (): ReadExceptionListSchema => ({ + id: ID, + list_id: LIST_ID, + namespace_type: NAMESPACE_TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..89cd869bd17c1 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.test.ts @@ -0,0 +1,126 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getReadExceptionListSchemaMock } from './index.mock'; +import { ReadExceptionListSchema, readExceptionListSchema } from '.'; + +describe('read_exception_list_schema', () => { + test('it should validate a typical exception list request', () => { + const payload = getReadExceptionListSchemaMock(); + const decoded = readExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id"', () => { + const payload = getReadExceptionListSchemaMock(); + delete payload.id; + const decoded = readExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "list_id"', () => { + const payload = getReadExceptionListSchemaMock(); + delete payload.list_id; + const decoded = readExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "namespace_type" but default to "single"', () => { + const payload = getReadExceptionListSchemaMock(); + delete payload.namespace_type; + const decoded = readExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getReadExceptionListSchemaMock()); + }); + + test('it should accept an undefined for "id", "list_id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getReadExceptionListSchemaMock(); + delete payload.id; + delete payload.namespace_type; + delete payload.list_id; + const output = getReadExceptionListSchemaMock(); + delete output.id; + delete output.list_id; + const decoded = readExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should accept an undefined for "id", "list_id"', () => { + const payload = getReadExceptionListSchemaMock(); + delete payload.id; + delete payload.list_id; + const decoded = readExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getReadExceptionListSchemaMock(); + delete payload.id; + delete payload.namespace_type; + const output = getReadExceptionListSchemaMock(); + delete output.id; + const decoded = readExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should accept an undefined for "list_id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getReadExceptionListSchemaMock(); + delete payload.namespace_type; + delete payload.list_id; + const output = getReadExceptionListSchemaMock(); + delete output.list_id; + const decoded = readExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ReadExceptionListSchema & { + extraKey?: string; + } = getReadExceptionListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = readExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.ts new file mode 100644 index 0000000000000..b4d9b7309fb5f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_exception_list_schema/index.ts @@ -0,0 +1,32 @@ +/* + * 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 * as t from 'io-ts'; + +import { NamespaceType } from '../../common/default_namespace'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { list_id } from '../../common/list_id'; +import { namespace_type } from '../../common/namespace_type'; + +export const readExceptionListSchema = t.exact( + t.partial({ + id, + list_id, + namespace_type, // defaults to 'single' if not set during decode + }) +); + +export type ReadExceptionListSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type ReadExceptionListSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..a239111231404 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { LIST_ID, LIST_ITEM_ID, VALUE } from '../../constants/index.mock'; + +import { ReadListItemSchema } from '.'; + +export const getReadListItemSchemaMock = (): ReadListItemSchema => ({ + id: LIST_ITEM_ID, + list_id: LIST_ID, + value: VALUE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..9370aa5e3d459 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.test.ts @@ -0,0 +1,117 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getReadListItemSchemaMock } from './index.mock'; +import { ReadListItemSchema, readListItemSchema } from '.'; + +describe('read_list_item_schema', () => { + test('it should validate a typical list item request', () => { + const payload = getReadListItemSchemaMock(); + const decoded = readListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id"', () => { + const payload = getReadListItemSchemaMock(); + delete payload.id; + const decoded = readListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "list_id"', () => { + const payload = getReadListItemSchemaMock(); + delete payload.list_id; + const decoded = readListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "value"', () => { + const payload = getReadListItemSchemaMock(); + delete payload.value; + const decoded = readListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id", "list_id", "value"', () => { + const payload = getReadListItemSchemaMock(); + delete payload.id; + delete payload.value; + delete payload.list_id; + const decoded = readListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id", "list_id"', () => { + const payload = getReadListItemSchemaMock(); + delete payload.id; + delete payload.list_id; + const decoded = readListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id", "value"', () => { + const payload = getReadListItemSchemaMock(); + delete payload.id; + delete payload.value; + const decoded = readListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "list_id", "value"', () => { + const payload = getReadListItemSchemaMock(); + delete payload.value; + delete payload.list_id; + const decoded = readListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ReadListItemSchema & { extraKey?: string } = getReadListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = readListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.ts new file mode 100644 index 0000000000000..571f37ff403e0 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_item_schema/index.ts @@ -0,0 +1,18 @@ +/* + * 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 * as t from 'io-ts'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { list_id } from '../../common/list_id'; +import { value } from '../../common/value'; + +export const readListItemSchema = t.exact(t.partial({ id, list_id, value })); + +export type ReadListItemSchema = t.OutputOf; +export type ReadListItemSchemaDecoded = RequiredKeepUndefined>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.mock.ts new file mode 100644 index 0000000000000..c82b343815540 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LIST_ID } from '../../constants/index.mock'; + +import { ReadListSchema } from '.'; + +export const getReadListSchemaMock = (): ReadListSchema => ({ + id: LIST_ID, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.test.ts new file mode 100644 index 0000000000000..1953341d2be41 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.test.ts @@ -0,0 +1,47 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getReadListSchemaMock } from './index.mock'; +import { ReadListSchema, readListSchema } from '.'; + +describe('read_list_schema', () => { + test('it should validate a typical list item request', () => { + const payload = getReadListSchemaMock(); + const decoded = readListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "id"', () => { + const payload = getReadListSchemaMock(); + // @ts-expect-error + delete payload.id; + const decoded = readListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ReadListSchema & { extraKey?: string } = getReadListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = readListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.ts new file mode 100644 index 0000000000000..6382a7c0ad975 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/read_list_schema/index.ts @@ -0,0 +1,18 @@ +/* + * 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 * as t from 'io-ts'; + +import { id } from '../../common/id'; + +export const readListSchema = t.exact( + t.type({ + id, + }) +); + +export type ReadListSchema = t.OutputOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..af6dc55b61da7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.mock.ts @@ -0,0 +1,17 @@ +/* + * 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 { FILTER, ID, LIST_ID, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { SummaryExceptionListSchema } from '.'; + +export const getSummaryExceptionListSchemaMock = (): SummaryExceptionListSchema => ({ + filter: FILTER, + id: ID, + list_id: LIST_ID, + namespace_type: NAMESPACE_TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..53a734ed034e7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.test.ts @@ -0,0 +1,136 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getSummaryExceptionListSchemaMock } from './index.mock'; +import { SummaryExceptionListSchema, summaryExceptionListSchema } from '.'; + +describe('summary_exception_list_schema', () => { + test('it should validate a typical exception list request', () => { + const payload = getSummaryExceptionListSchemaMock(); + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "filter"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.filter; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "list_id"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.list_id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "namespace_type" but default to "single"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.namespace_type; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(getSummaryExceptionListSchemaMock()); + }); + + test('it should accept an undefined for "id", "list_id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.id; + delete payload.namespace_type; + delete payload.list_id; + const output = getSummaryExceptionListSchemaMock(); + delete output.id; + delete output.list_id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should accept an undefined for "id", "list_id"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.id; + delete payload.list_id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.id; + delete payload.namespace_type; + const output = getSummaryExceptionListSchemaMock(); + delete output.id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should accept an undefined for "list_id", "namespace_type" but default "namespace_type" to "single"', () => { + const payload = getSummaryExceptionListSchemaMock(); + delete payload.namespace_type; + delete payload.list_id; + const output = getSummaryExceptionListSchemaMock(); + delete output.list_id; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(output); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: SummaryExceptionListSchema & { + extraKey?: string; + } = getSummaryExceptionListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = summaryExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = foldLeftRight(checked); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts new file mode 100644 index 0000000000000..6be4f0c57b086 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/summary_exception_list_schema/index.ts @@ -0,0 +1,35 @@ +/* + * 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 * as t from 'io-ts'; + +import { NamespaceType } from '../../common/default_namespace'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { filter, Filter } from '../../common/filter'; +import { list_id } from '../../common/list_id'; +import { namespace_type } from '../../common/namespace_type'; + +export const summaryExceptionListSchema = t.exact( + t.partial({ + filter, + id, + list_id, + namespace_type, // defaults to 'single' if not set during decode + }) +); + +export type SummaryExceptionListSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type SummaryExceptionListSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'namespace_type' +> & { + namespace_type: NamespaceType; + filter: Filter; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..57244aac0426f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.mock.ts @@ -0,0 +1,35 @@ +/* + * 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 { + COMMENTS, + DESCRIPTION, + ENTRIES, + ID, + ITEM_TYPE, + LIST_ITEM_ID, + META, + NAME, + OS_TYPES, + TAGS, +} from '../../constants/index.mock'; + +import { UpdateEndpointListItemSchema } from '.'; + +export const getUpdateEndpointListItemSchemaMock = (): UpdateEndpointListItemSchema => ({ + _version: undefined, + comments: COMMENTS, + description: DESCRIPTION, + entries: ENTRIES, + id: ID, + item_id: LIST_ITEM_ID, + meta: META, + name: NAME, + os_types: OS_TYPES, + tags: TAGS, + type: ITEM_TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..1def91ca1a8e2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.test.ts @@ -0,0 +1,138 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { UpdateEndpointListItemSchema, updateEndpointListItemSchema } from '.'; +import { getUpdateEndpointListItemSchemaMock } from './index.mock'; + +describe('update_endpoint_list_item_schema', () => { + test('it should validate a typical list item request', () => { + const payload = getUpdateEndpointListItemSchemaMock(); + const decoded = updateEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not accept an undefined for "description"', () => { + const payload = getUpdateEndpointListItemSchemaMock(); + // @ts-expect-error + delete payload.description; + const decoded = updateEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not accept an undefined for "name"', () => { + const payload = getUpdateEndpointListItemSchemaMock(); + // @ts-expect-error + delete payload.name; + const decoded = updateEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not accept an undefined for "type"', () => { + const payload = getUpdateEndpointListItemSchemaMock(); + // @ts-expect-error + delete payload.type; + const decoded = updateEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not accept a value for "list_id"', () => { + const payload: UpdateEndpointListItemSchema & { + list_id?: string; + } = getUpdateEndpointListItemSchemaMock(); + payload.list_id = 'some new list_id'; + const decoded = updateEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "list_id"']); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "meta" but strip it out', () => { + const payload = getUpdateEndpointListItemSchemaMock(); + const outputPayload = getUpdateEndpointListItemSchemaMock(); + delete payload.meta; + const decoded = updateEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete outputPayload.meta; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should accept an undefined for "comments" but return an array', () => { + const inputPayload = getUpdateEndpointListItemSchemaMock(); + const outputPayload = getUpdateEndpointListItemSchemaMock(); + delete inputPayload.comments; + outputPayload.comments = []; + const decoded = updateEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should NOT accept an undefined for "entries"', () => { + const inputPayload = getUpdateEndpointListItemSchemaMock(); + const outputPayload = getUpdateEndpointListItemSchemaMock(); + // @ts-expect-error + delete inputPayload.entries; + outputPayload.entries = []; + const decoded = updateEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "tags" but return an array', () => { + const inputPayload = getUpdateEndpointListItemSchemaMock(); + const outputPayload = getUpdateEndpointListItemSchemaMock(); + delete inputPayload.tags; + outputPayload.tags = []; + const decoded = updateEndpointListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: UpdateEndpointListItemSchema & { + extraKey?: string; + } = getUpdateEndpointListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = updateEndpointListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.ts new file mode 100644 index 0000000000000..e301137058afc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_endpoint_list_item_schema/index.ts @@ -0,0 +1,57 @@ +/* + * 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 * as t from 'io-ts'; + +import { DefaultUpdateCommentsArray } from '../../common/default_update_comments_array'; +import { exceptionListItemType } from '../../common/exception_list_item_type'; +import { nonEmptyEntriesArray } from '../../common/non_empty_entries_array'; +import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; +import { description } from '../../common/description'; +import { name } from '../../common/name'; +import { _version } from '../../common/underscore_version'; +import { id } from '../../common/id'; +import { meta } from '../../common/meta'; +import { Tags, tags } from '../../common/tags'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { UpdateCommentsArray } from '../../common/update_comment'; +import { EntriesArray } from '../../common/entries'; + +export const updateEndpointListItemSchema = t.intersection([ + t.exact( + t.type({ + description, + entries: nonEmptyEntriesArray, + name, + type: exceptionListItemType, + }) + ), + t.exact( + t.partial({ + _version, // defaults to undefined if not set during decode + comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode + id, // defaults to undefined if not set during decode + item_id: t.union([t.string, t.undefined]), + meta, // defaults to undefined if not set during decode + os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode + tags, // defaults to empty array if not set during decode + }) + ), +]); + +export type UpdateEndpointListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type UpdateEndpointListItemSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'tags' | 'entries' | 'comments' +> & { + comments: UpdateCommentsArray; + tags: Tags; + entries: EntriesArray; + os_types: OsTypeArray; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..c7560348179dc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.mock.ts @@ -0,0 +1,51 @@ +/* + * 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 { + COMMENTS, + DESCRIPTION, + ENTRIES, + ID, + ITEM_ID, + ITEM_TYPE, + LIST_ITEM_ID, + META, + NAME, + NAMESPACE_TYPE, + OS_TYPES, + TAGS, +} from '../../constants/index.mock'; + +import { UpdateExceptionListItemSchema } from '.'; + +export const getUpdateExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({ + _version: undefined, + comments: COMMENTS, + description: DESCRIPTION, + entries: ENTRIES, + id: ID, + item_id: LIST_ITEM_ID, + meta: META, + name: NAME, + namespace_type: NAMESPACE_TYPE, + os_types: ['linux'], + tags: TAGS, + type: ITEM_TYPE, +}); + +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + * after doing a get of the structure. + */ +export const getUpdateMinimalExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({ + description: DESCRIPTION, + entries: ENTRIES, + item_id: ITEM_ID, + name: NAME, + os_types: OS_TYPES, + type: ITEM_TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..0adbf1224d720 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.test.ts @@ -0,0 +1,160 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { UpdateExceptionListItemSchema, updateExceptionListItemSchema } from '.'; +import { getUpdateExceptionListItemSchemaMock } from './index.mock'; + +describe('update_exception_list_item_schema', () => { + test('it should validate a typical exception list item request', () => { + const payload = getUpdateExceptionListItemSchemaMock(); + const decoded = updateExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not accept an undefined for "description"', () => { + const payload = getUpdateExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.description; + const decoded = updateExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not accept an undefined for "name"', () => { + const payload = getUpdateExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.name; + const decoded = updateExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not accept an undefined for "type"', () => { + const payload = getUpdateExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.type; + const decoded = updateExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not accept a value for "list_id"', () => { + const payload: UpdateExceptionListItemSchema & { + list_id?: string; + } = getUpdateExceptionListItemSchemaMock(); + payload.list_id = 'some new list_id'; + const decoded = updateExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "list_id"']); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "meta" but strip it out', () => { + const payload = getUpdateExceptionListItemSchemaMock(); + const outputPayload = getUpdateExceptionListItemSchemaMock(); + delete payload.meta; + const decoded = updateExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete outputPayload.meta; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should accept an undefined for "comments" but return an array', () => { + const inputPayload = getUpdateExceptionListItemSchemaMock(); + const outputPayload = getUpdateExceptionListItemSchemaMock(); + delete inputPayload.comments; + outputPayload.comments = []; + const decoded = updateExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should NOT accept an undefined for "entries"', () => { + const inputPayload = getUpdateExceptionListItemSchemaMock(); + const outputPayload = getUpdateExceptionListItemSchemaMock(); + // @ts-expect-error + delete inputPayload.entries; + outputPayload.entries = []; + const decoded = updateExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "namespace_type" but return enum "single"', () => { + const inputPayload = getUpdateExceptionListItemSchemaMock(); + const outputPayload = getUpdateExceptionListItemSchemaMock(); + delete inputPayload.namespace_type; + outputPayload.namespace_type = 'single'; + const decoded = updateExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should accept an undefined for "tags" but return an array', () => { + const inputPayload = getUpdateExceptionListItemSchemaMock(); + const outputPayload = getUpdateExceptionListItemSchemaMock(); + delete inputPayload.tags; + outputPayload.tags = []; + const decoded = updateExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should accept an undefined for "item_id" and generate a correct body not counting the uuid', () => { + const inputPayload = getUpdateExceptionListItemSchemaMock(); + delete inputPayload.item_id; + const decoded = updateExceptionListItemSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as UpdateExceptionListItemSchema).item_id; + expect(message.schema).toEqual(inputPayload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: UpdateExceptionListItemSchema & { + extraKey?: string; + } = getUpdateExceptionListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = updateExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.ts new file mode 100644 index 0000000000000..910acbe2c942f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_item_schema/index.ts @@ -0,0 +1,64 @@ +/* + * 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 * as t from 'io-ts'; +import { ExceptionListItemEntryArray } from '@kbn/securitysolution-exceptions-common/api'; +import { NamespaceType } from '../../common/default_namespace'; +import { DefaultUpdateCommentsArray } from '../../common/default_update_comments_array'; +import { exceptionListItemType } from '../../common/exception_list_item_type'; +import { nonEmptyEntriesArray } from '../../common/non_empty_entries_array'; +import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { Tags, tags } from '../../common/tags'; +import { UpdateCommentsArray } from '../../common/update_comment'; +import { description } from '../../common/description'; +import { name } from '../../common/name'; +import { _version } from '../../common/underscore_version'; +import { id } from '../../common/id'; +import { item_id } from '../../common/item_id'; +import { meta } from '../../common/meta'; +import { namespace_type } from '../../common/namespace_type'; +import { ExpireTimeOrUndefined, expireTimeOrUndefined } from '../../common'; + +export const updateExceptionListItemSchema = t.intersection([ + t.exact( + t.type({ + description, + entries: nonEmptyEntriesArray, + name, + type: exceptionListItemType, + }) + ), + t.exact( + t.partial({ + _version, // defaults to undefined if not set during decode + comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode + expire_time: expireTimeOrUndefined, + id, // defaults to undefined if not set during decode + item_id, + meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode + os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode + tags, // defaults to empty array if not set during decode + }) + ), +]); + +export type UpdateExceptionListItemSchema = t.OutputOf; + +// This type is used after a decode since some things are defaults after a decode. +export type UpdateExceptionListItemSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'tags' | 'entries' | 'namespace_type' | 'comments' | 'os_types' | 'expire_time' +> & { + comments: UpdateCommentsArray; + tags: Tags; + entries: ExceptionListItemEntryArray; + namespace_type: NamespaceType; + os_types: OsTypeArray; + expire_time: ExpireTimeOrUndefined; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..9aac2453a7beb --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.mock.ts @@ -0,0 +1,34 @@ +/* + * 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 { DESCRIPTION, ID, LIST_ID, META, NAME, NAMESPACE_TYPE } from '../../constants/index.mock'; + +import { UpdateExceptionListSchema } from '.'; + +export const getUpdateExceptionListSchemaMock = (): UpdateExceptionListSchema => ({ + _version: undefined, + description: DESCRIPTION, + id: ID, + list_id: LIST_ID, + meta: META, + name: NAME, + namespace_type: NAMESPACE_TYPE, + os_types: [], + tags: ['malware'], + type: 'endpoint', +}); + +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + * after doing a get of the structure. + */ +export const getUpdateMinimalExceptionListSchemaMock = (): UpdateExceptionListSchema => ({ + description: DESCRIPTION, + list_id: LIST_ID, + name: NAME, + type: 'endpoint', +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..029751ac4d144 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.test.ts @@ -0,0 +1,121 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { UpdateExceptionListSchema, updateExceptionListSchema } from '.'; +import { getUpdateExceptionListSchemaMock } from './index.mock'; + +describe('update_exception_list_schema', () => { + test('it should validate a typical exception list request', () => { + const payload = getUpdateExceptionListSchemaMock(); + const decoded = updateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should not accept an undefined for "description"', () => { + const payload = getUpdateExceptionListSchemaMock(); + // @ts-expect-error + delete payload.description; + const decoded = updateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not accept an undefined for "name"', () => { + const payload = getUpdateExceptionListSchemaMock(); + // @ts-expect-error + delete payload.name; + const decoded = updateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not accept an undefined for "type"', () => { + const payload = getUpdateExceptionListSchemaMock(); + // @ts-expect-error + delete payload.type; + const decoded = updateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "meta" but strip it out', () => { + const payload = getUpdateExceptionListSchemaMock(); + const outputPayload = getUpdateExceptionListSchemaMock(); + delete payload.meta; + const decoded = updateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete outputPayload.meta; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should accept an undefined for "namespace_type" but return enum "single"', () => { + const inputPayload = getUpdateExceptionListSchemaMock(); + const outputPayload = getUpdateExceptionListSchemaMock(); + delete inputPayload.namespace_type; + outputPayload.namespace_type = 'single'; + const decoded = updateExceptionListSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should accept an undefined for "tags" but return an array', () => { + const inputPayload = getUpdateExceptionListSchemaMock(); + const outputPayload = getUpdateExceptionListSchemaMock(); + delete inputPayload.tags; + outputPayload.tags = []; + const decoded = updateExceptionListSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should accept an undefined for "list_id" and generate a correct body not counting the uuid', () => { + const inputPayload = getUpdateExceptionListSchemaMock(); + delete inputPayload.list_id; + const decoded = updateExceptionListSchema.decode(inputPayload); + const checked = exactCheck(inputPayload, decoded); + const message = pipe(checked, foldLeftRight); + delete (message.schema as UpdateExceptionListSchema).list_id; + expect(message.schema).toEqual(inputPayload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: UpdateExceptionListSchema & { + extraKey?: string; + } = getUpdateExceptionListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = updateExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.ts new file mode 100644 index 0000000000000..be4006c3efa18 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_exception_list_schema/index.ts @@ -0,0 +1,56 @@ +/* + * 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 * as t from 'io-ts'; + +import { version } from '@kbn/securitysolution-io-ts-types'; +import { OsTypeArray, osTypeArrayOrUndefined } from '../../common/os_type'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { Tags, tags } from '../../common/tags'; +import { NamespaceType } from '../../common/default_namespace'; +import { description } from '../../common/description'; +import { name } from '../../common/name'; +import { _version } from '../../common/underscore_version'; +import { exceptionListType } from '../../common/exception_list'; +import { id } from '../../common/id'; +import { list_id } from '../../common/list_id'; +import { meta } from '../../common/meta'; +import { namespace_type } from '../../common/namespace_type'; + +export const updateExceptionListSchema = t.intersection([ + t.exact( + t.type({ + description, + name, + type: exceptionListType, + }) + ), + t.exact( + t.partial({ + _version, // defaults to undefined if not set during decode + id, // defaults to undefined if not set during decode + list_id, // defaults to undefined if not set during decode + meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode + os_types: osTypeArrayOrUndefined, // defaults to empty array if not set during decode + tags, // defaults to empty array if not set during decode + version, // defaults to undefined if not set during decode + }) + ), +]); + +export type UpdateExceptionListSchema = t.OutputOf; + +// This type is used after a decode since the arrays turn into defaults of empty arrays. +export type UpdateExceptionListSchemaDecoded = Omit< + RequiredKeepUndefined>, + 'tags | namespace_type' | 'os_types' +> & { + tags: Tags; + namespace_type: NamespaceType; + os_types: OsTypeArray; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..7d65f59aa8cda --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ID, LIST_ITEM_ID, META, VALUE } from '../../constants/index.mock'; + +import { UpdateListItemSchema } from '.'; + +export const getUpdateListItemSchemaMock = (): UpdateListItemSchema => ({ + id: ID, + meta: META, + value: VALUE, +}); + +/** + * Useful for end to end testing + */ +export const getUpdateMinimalListItemSchemaMock = (): UpdateListItemSchema => ({ + id: LIST_ITEM_ID, + value: VALUE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..ca6402455aabe --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.test.ts @@ -0,0 +1,48 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { UpdateListItemSchema, updateListItemSchema } from '.'; +import { getUpdateListItemSchemaMock } from './index.mock'; + +describe('update_list_item_schema', () => { + test('it should validate a typical list item request', () => { + const payload = getUpdateListItemSchemaMock(); + const decoded = updateListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "meta" but strip it out', () => { + const payload = getUpdateListItemSchemaMock(); + const outputPayload = getUpdateListItemSchemaMock(); + delete payload.meta; + const decoded = updateListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete outputPayload.meta; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: UpdateListItemSchema & { + extraKey?: string; + } = getUpdateListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = updateListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.ts new file mode 100644 index 0000000000000..2df22b5c57b74 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_item_schema/index.ts @@ -0,0 +1,34 @@ +/* + * 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 * as t from 'io-ts'; + +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { _version } from '../../common/underscore_version'; +import { id } from '../../common/id'; +import { value } from '../../common/value'; +import { meta } from '../../common/meta'; + +export const updateListItemSchema = t.intersection([ + t.exact( + t.type({ + id, + value, + }) + ), + t.exact( + t.partial({ + _version, // defaults to undefined if not set during decode + meta, // defaults to undefined if not set during decode + }) + ), +]); + +export type UpdateListItemSchema = t.OutputOf; +export type UpdateListItemSchemaDecoded = RequiredKeepUndefined< + t.TypeOf +>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.mock.ts new file mode 100644 index 0000000000000..99362d8ef8a7e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.mock.ts @@ -0,0 +1,28 @@ +/* + * 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 { DESCRIPTION, LIST_ID, META, NAME, _VERSION } from '../../constants/index.mock'; + +import { UpdateListSchema } from '.'; + +export const getUpdateListSchemaMock = (): UpdateListSchema => ({ + _version: _VERSION, + description: DESCRIPTION, + id: LIST_ID, + meta: META, + name: NAME, +}); + +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + * after doing a get of the structure. + */ +export const getUpdateMinimalListSchemaMock = (): UpdateListSchema => ({ + description: DESCRIPTION, + id: LIST_ID, + name: NAME, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.test.ts new file mode 100644 index 0000000000000..c35861f66e910 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.test.ts @@ -0,0 +1,48 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { UpdateListSchema, updateListSchema } from '.'; +import { getUpdateListSchemaMock } from './index.mock'; + +describe('update_list_schema', () => { + test('it should validate a typical list request', () => { + const payload = getUpdateListSchemaMock(); + const decoded = updateListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "meta" but strip it out', () => { + const payload = getUpdateListSchemaMock(); + const outputPayload = getUpdateListSchemaMock(); + delete payload.meta; + const decoded = updateListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + delete outputPayload.meta; + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(outputPayload); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: UpdateListSchema & { + extraKey?: string; + } = getUpdateListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = updateListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.ts new file mode 100644 index 0000000000000..c6182af2f23fa --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/request/update_list_schema/index.ts @@ -0,0 +1,36 @@ +/* + * 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 * as t from 'io-ts'; + +import { version } from '@kbn/securitysolution-io-ts-types'; +import { RequiredKeepUndefined } from '../../common/required_keep_undefined'; +import { id } from '../../common/id'; +import { name } from '../../common/name'; +import { description } from '../../common/description'; +import { _version } from '../../common/underscore_version'; +import { meta } from '../../common/meta'; + +export const updateListSchema = t.intersection([ + t.exact( + t.type({ + description, + id, + name, + }) + ), + t.exact( + t.partial({ + _version, // defaults to undefined if not set during decode + meta, // defaults to undefined if not set during decode + version, // defaults to undefined if not set during decode + }) + ), +]); + +export type UpdateListSchema = t.OutputOf; +export type UpdateListSchemaDecoded = RequiredKeepUndefined>; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.mock.ts new file mode 100644 index 0000000000000..2c4ac68f46132 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.mock.ts @@ -0,0 +1,12 @@ +/* + * 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 { AcknowledgeSchema } from '.'; + +export const getAcknowledgeSchemaResponseMock = (): AcknowledgeSchema => ({ + acknowledged: true, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.test.ts new file mode 100644 index 0000000000000..4fd4adf861bbd --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.test.ts @@ -0,0 +1,48 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getAcknowledgeSchemaResponseMock } from './index.mock'; +import { AcknowledgeSchema, acknowledgeSchema } from '.'; + +describe('acknowledge_schema', () => { + test('it should validate a typical response', () => { + const payload = getAcknowledgeSchemaResponseMock(); + const decoded = acknowledgeSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + test('it should NOT accept an undefined for "ok"', () => { + const payload = getAcknowledgeSchemaResponseMock(); + // @ts-expect-error + delete payload.acknowledged; + const decoded = acknowledgeSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "acknowledged"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: AcknowledgeSchema & { extraKey?: string } = getAcknowledgeSchemaResponseMock(); + payload.extraKey = 'some new value'; + const decoded = acknowledgeSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.ts new file mode 100644 index 0000000000000..97a0dc23682c4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/acknowledge_schema/index.ts @@ -0,0 +1,12 @@ +/* + * 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 * as t from 'io-ts'; + +export const acknowledgeSchema = t.exact(t.type({ acknowledged: t.boolean })); + +export type AcknowledgeSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.test.ts new file mode 100644 index 0000000000000..2ac63d9719e29 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.test.ts @@ -0,0 +1,73 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { CreateEndpointListSchema, createEndpointListSchema } from '.'; +import { getExceptionListSchemaMock } from '../exception_list_schema/index.mock'; + +describe('create_endpoint_list_schema', () => { + test('it should validate a typical endpoint list response', () => { + const payload = getExceptionListSchemaMock(); + const decoded = createEndpointListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an empty object when an endpoint list already exists', () => { + const payload: CreateEndpointListSchema = {}; + const decoded = createEndpointListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "list_id"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.list_id; + const decoded = createEndpointListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'invalid keys "_version,created_at,created_by,description,id,immutable,meta,{},name,namespace_type,os_types,["linux"],tags,["user added string for a tag","malware"],tie_breaker_id,type,updated_at,updated_by,version"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT allow missing fields', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.list_id; + const decoded = createEndpointListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors)).length).toEqual(1); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: CreateEndpointListSchema & { + extraKey?: string; + } = getExceptionListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = createEndpointListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.ts new file mode 100644 index 0000000000000..44f3629973a06 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/create_endpoint_list_schema/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; +import { exceptionListSchema } from '../exception_list_schema'; + +export const createEndpointListSchema = t.union([exceptionListSchema, t.exact(t.type({}))]); + +export type CreateEndpointListSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..fad9dc5990a85 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.mock.ts @@ -0,0 +1,70 @@ +/* + * 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 { + COMMENTS, + DATE_NOW, + DESCRIPTION, + ELASTIC_USER, + ENTRIES, + ITEM_ID, + ITEM_TYPE, + LIST_ID, + META, + NAME, + NAMESPACE_TYPE, + OS_TYPES, + TIE_BREAKER, + USER, +} from '../../constants/index.mock'; + +import { ExceptionListItemSchema } from '.'; + +export const getExceptionListItemSchemaMock = ( + overrides?: Partial +): ExceptionListItemSchema => ({ + _version: undefined, + comments: COMMENTS, + created_at: DATE_NOW, + created_by: USER, + description: DESCRIPTION, + entries: ENTRIES, + expire_time: undefined, + id: '1', + item_id: 'endpoint_list_item', + list_id: 'endpoint_list_id', + meta: META, + name: NAME, + namespace_type: NAMESPACE_TYPE, + os_types: ['linux'], + tags: ['user added string for a tag', 'malware'], + tie_breaker_id: TIE_BREAKER, + type: ITEM_TYPE, + updated_at: DATE_NOW, + updated_by: USER, + ...(overrides || {}), +}); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getExceptionListItemResponseMockWithoutAutoGeneratedValues = + (): Partial => ({ + comments: [], + created_by: ELASTIC_USER, + description: DESCRIPTION, + entries: ENTRIES, + item_id: ITEM_ID, + list_id: LIST_ID, + name: NAME, + namespace_type: 'single', + os_types: OS_TYPES, + tags: [], + type: ITEM_TYPE, + updated_by: ELASTIC_USER, + }); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..1231764ae7f52 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.test.ts @@ -0,0 +1,240 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getExceptionListItemSchemaMock } from './index.mock'; +import { ExceptionListItemSchema, exceptionListItemSchema } from '.'; + +describe('exception_list_item_schema', () => { + test('it should validate a typical exception list item response', () => { + const payload = getExceptionListItemSchemaMock(); + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "id"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.id; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "list_id"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.list_id; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "item_id"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.item_id; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "item_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "comments"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.comments; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "comments"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "entries"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.entries; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "name"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.name; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "namespace_type" and return "single" as a default value for "namespace_type"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.namespace_type; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect((message.schema as ExceptionListItemSchema).namespace_type).toEqual('single'); + }); + + test('it should NOT accept an undefined for "description"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.description; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "meta"', () => { + const payload = getExceptionListItemSchemaMock(); + delete payload.meta; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "created_at"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.created_at; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "created_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "created_by"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.created_by; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "created_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "tie_breaker_id"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.tie_breaker_id; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "tie_breaker_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "type"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.type; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "updated_at"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.updated_at; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "updated_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "updated_by"', () => { + const payload = getExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.updated_by; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "updated_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ExceptionListItemSchema & { + extraKey?: string; + } = getExceptionListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = exceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.ts new file mode 100644 index 0000000000000..f3f3986c4ea37 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_item_schema/index.ts @@ -0,0 +1,54 @@ +/* + * 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 * as t from 'io-ts'; + +import { namespace_type } from '../../common/namespace_type'; +import { metaOrUndefined } from '../../common/meta'; +import { name } from '../../common/name'; +import { created_at } from '../../common/created_at'; +import { created_by } from '../../common/created_by'; +import { id } from '../../common/id'; +import { tie_breaker_id } from '../../common/tie_breaker_id'; +import { updated_at } from '../../common/updated_at'; +import { updated_by } from '../../common/updated_by'; +import { list_id } from '../../common/list_id'; +import { description } from '../../common/description'; +import { osTypeArray } from '../../common/os_type'; +import { tags } from '../../common/tags'; +import { _versionOrUndefined } from '../../common/underscore_version'; +import { commentsArray } from '../../common/comment'; +import { entriesArray } from '../../common/entries'; +import { item_id } from '../../common/item_id'; +import { exceptionListItemType } from '../../common/exception_list_item_type'; +import { expireTimeOrUndefined } from '../../common/expire_time'; + +export const exceptionListItemSchema = t.exact( + t.type({ + _version: _versionOrUndefined, + comments: commentsArray, + created_at, + created_by, + description, + entries: entriesArray, + expire_time: expireTimeOrUndefined, + id, + item_id, + list_id, + meta: metaOrUndefined, + name, + namespace_type, + os_types: osTypeArray, + tags, + tie_breaker_id, + type: exceptionListItemType, + updated_at, + updated_by, + }) +); + +export type ExceptionListItemSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..07b47f91fead8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts @@ -0,0 +1,77 @@ +/* + * 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 { + DATE_NOW, + DESCRIPTION, + ELASTIC_USER, + ENDPOINT_TYPE, + IMMUTABLE, + LIST_ID, + META, + NAME, + TIE_BREAKER, + USER, + VERSION, + _VERSION, +} from '../../constants/index.mock'; +import { + ENDPOINT_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, + ENDPOINT_TRUSTED_APPS_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_NAME, +} from '@kbn/securitysolution-list-constants'; + +import { ExceptionListSchema } from '.'; + +export const getExceptionListSchemaMock = (): ExceptionListSchema => ({ + _version: _VERSION, + created_at: DATE_NOW, + created_by: USER, + description: DESCRIPTION, + id: '1', + immutable: IMMUTABLE, + list_id: ENDPOINT_LIST_ID, + meta: META, + name: 'Sample Endpoint Exception List', + namespace_type: 'agnostic', + os_types: ['linux'], + tags: ['user added string for a tag', 'malware'], + tie_breaker_id: TIE_BREAKER, + type: ENDPOINT_TYPE, + updated_at: DATE_NOW, + updated_by: 'user_name', + version: VERSION, +}); + +export const getTrustedAppsListSchemaMock = (): ExceptionListSchema => { + return { + ...getExceptionListSchemaMock(), + description: ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + name: ENDPOINT_TRUSTED_APPS_LIST_NAME, + }; +}; + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getExceptionResponseMockWithoutAutoGeneratedValues = + (): Partial => ({ + created_by: ELASTIC_USER, + description: DESCRIPTION, + immutable: IMMUTABLE, + list_id: LIST_ID, + name: NAME, + namespace_type: 'single', + os_types: [], + tags: [], + type: ENDPOINT_TYPE, + updated_by: ELASTIC_USER, + version: VERSION, + }); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..b043cde4c3f0d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.test.ts @@ -0,0 +1,198 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getExceptionListSchemaMock } from './index.mock'; +import { ExceptionListSchema, exceptionListSchema } from '.'; + +describe('exception_list_schema', () => { + test('it should validate a typical exception list response', () => { + const payload = getExceptionListSchemaMock(); + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "id"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.id; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "list_id"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.list_id; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "name"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.name; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "namespace_type" and make "namespace_type" that of "single"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.namespace_type; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect((message.schema as ExceptionListSchema).namespace_type).toEqual('single'); + }); + + test('it should NOT accept an undefined for "description"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.description; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "meta"', () => { + const payload = getExceptionListSchemaMock(); + delete payload.meta; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "created_at"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.created_at; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "created_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "created_by"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.created_by; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "created_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "tie_breaker_id"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.tie_breaker_id; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "tie_breaker_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "type"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.type; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "updated_at"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.updated_at; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "updated_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "updated_by"', () => { + const payload = getExceptionListSchemaMock(); + // @ts-expect-error + delete payload.updated_by; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "updated_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ExceptionListSchema & { + extraKey?: string; + } = getExceptionListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = exceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.ts new file mode 100644 index 0000000000000..e04eadb707657 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.ts @@ -0,0 +1,50 @@ +/* + * 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 * as t from 'io-ts'; + +import { version } from '@kbn/securitysolution-io-ts-types'; +import { _versionOrUndefined } from '../../common/underscore_version'; +import { namespace_type } from '../../common/namespace_type'; +import { metaOrUndefined } from '../../common/meta'; +import { name } from '../../common/name'; +import { created_at } from '../../common/created_at'; +import { created_by } from '../../common/created_by'; +import { id } from '../../common/id'; +import { tie_breaker_id } from '../../common/tie_breaker_id'; +import { immutable } from '../../common/immutable'; +import { updated_at } from '../../common/updated_at'; +import { updated_by } from '../../common/updated_by'; +import { list_id } from '../../common/list_id'; +import { description } from '../../common/description'; +import { osTypeArray } from '../../common/os_type'; +import { exceptionListType } from '../../common/exception_list'; +import { tags } from '../../common/tags'; + +export const exceptionListSchema = t.exact( + t.type({ + _version: _versionOrUndefined, + created_at, + created_by, + description, + id, + immutable, + list_id, + meta: metaOrUndefined, + name, + namespace_type, + os_types: osTypeArray, + tags, + tie_breaker_id, + type: exceptionListType, + updated_at, + updated_by, + version, + }) +); + +export type ExceptionListSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts new file mode 100644 index 0000000000000..0acac1da648d5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ExceptionListSummarySchema } from '.'; + +export const getListSummaryResponseMock = (): ExceptionListSummarySchema => ({ + windows: 0, + linux: 1, + macos: 2, + total: 3, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts new file mode 100644 index 0000000000000..b4b6de2e25d1e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.test.ts @@ -0,0 +1,93 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getListSummaryResponseMock } from './index.mock'; +import { ExceptionListSummarySchema, exceptionListSummarySchema } from '.'; + +describe('list_summary_schema', () => { + test('it should validate a typical list summary response', () => { + const payload = getListSummaryResponseMock(); + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "windows"', () => { + const payload = getListSummaryResponseMock(); + // @ts-expect-error + delete payload.windows; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "windows"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "linux"', () => { + const payload = getListSummaryResponseMock(); + // @ts-expect-error + delete payload.linux; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "linux"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "macos"', () => { + const payload = getListSummaryResponseMock(); + // @ts-expect-error + delete payload.macos; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "macos"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "total"', () => { + const payload = getListSummaryResponseMock(); + // @ts-expect-error + delete payload.total; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "total"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ExceptionListSummarySchema & { + extraKey?: string; + } = getListSummaryResponseMock(); + payload.extraKey = 'some new value'; + const decoded = exceptionListSummarySchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts new file mode 100644 index 0000000000000..7414ca257fbd2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_summary_schema/index.ts @@ -0,0 +1,20 @@ +/* + * 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 { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; +import * as t from 'io-ts'; + +export const exceptionListSummarySchema = t.exact( + t.type({ + windows: PositiveInteger, + linux: PositiveInteger, + macos: PositiveInteger, + total: PositiveInteger, + }) +); + +export type ExceptionListSummarySchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.mock.ts new file mode 100644 index 0000000000000..75330f4937432 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FoundAllListItemsSchema } from '.'; +import { getListItemResponseMock } from '../list_item_schema/index.mock'; + +export const getFoundAllListItemsSchemaMock = (): FoundAllListItemsSchema => ({ + data: [getListItemResponseMock()], + total: 1, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.ts new file mode 100644 index 0000000000000..c5812499b3e77 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_all_list_items_schema/index.ts @@ -0,0 +1,20 @@ +/* + * 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 * as t from 'io-ts'; + +import { listItemSchema } from '../list_item_schema'; +import { total } from '../../common/total'; + +export const foundAllListItemsSchema = t.exact( + t.type({ + data: t.array(listItemSchema), + total, + }) +); + +export type FoundAllListItemsSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..6f8592320895d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { FoundExceptionListItemSchema } from '.'; +import { getExceptionListItemSchemaMock } from '../exception_list_item_schema/index.mock'; + +export const getFoundExceptionListItemSchemaMock = (): FoundExceptionListItemSchema => ({ + data: [getExceptionListItemSchemaMock()], + page: 1, + per_page: 1, + total: 1, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..33d26ca32a5bc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.test.ts @@ -0,0 +1,152 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getFoundExceptionListItemSchemaMock } from './index.mock'; +import { FoundExceptionListItemSchema, foundExceptionListItemSchema } from '.'; +import { ExceptionListItemSchema } from '../exception_list_item_schema'; +import { getExceptionListItemSchemaMock } from '../exception_list_item_schema/index.mock'; + +describe('found_exception_list_item_schema', () => { + test('it should validate a typical exception list response', () => { + const payload = getFoundExceptionListItemSchemaMock(); + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept a malformed exception list item within "data"', () => { + const item: Omit & { + entries?: string; + } = { ...getExceptionListItemSchemaMock(), entries: 'I should be an array' }; + const payload: Omit & { + data?: Array< + Omit & { + entries?: string; + } + >; + } = { ...getFoundExceptionListItemSchemaMock(), data: [item] }; + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "I should be an array" supplied to "data,entries"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept a string for "page"', () => { + const payload: Omit & { + page?: string; + } = { ...getFoundExceptionListItemSchemaMock(), page: '1' }; + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "page"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept a string for "per_page"', () => { + const payload: Omit & { + per_page?: string; + } = { ...getFoundExceptionListItemSchemaMock(), per_page: '20' }; + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "20" supplied to "per_page"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept a string for "total"', () => { + const payload: Omit & { + total?: string; + } = { ...getFoundExceptionListItemSchemaMock(), total: '1' }; + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "total"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "page"', () => { + const payload = getFoundExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.page; + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "page"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "per_page"', () => { + const payload = getFoundExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.per_page; + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "per_page"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "total"', () => { + const payload = getFoundExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.total; + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "total"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "data"', () => { + const payload = getFoundExceptionListItemSchemaMock(); + // @ts-expect-error + delete payload.data; + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "data"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: FoundExceptionListItemSchema & { + extraKey?: string; + } = getFoundExceptionListItemSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = foundExceptionListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.ts new file mode 100644 index 0000000000000..50f57bf424593 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_item_schema/index.ts @@ -0,0 +1,32 @@ +/* + * 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 * as t from 'io-ts'; + +import { page } from '../../common/page'; +import { per_page } from '../../common/per_page'; +import { pitId } from '../../common/pit'; +import { total } from '../../common/total'; +import { exceptionListItemSchema } from '../exception_list_item_schema'; + +export const foundExceptionListItemSchema = t.intersection([ + t.exact( + t.type({ + data: t.array(exceptionListItemSchema), + page, + per_page, + total, + }) + ), + t.exact( + t.partial({ + pit: pitId, + }) + ), +]); + +export type FoundExceptionListItemSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.mock.ts new file mode 100644 index 0000000000000..8a6d9fe2d2a79 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { FoundExceptionListSchema } from '.'; +import { getExceptionListSchemaMock } from '../exception_list_schema/index.mock'; + +export const getFoundExceptionListSchemaMock = (): FoundExceptionListSchema => ({ + data: [getExceptionListSchemaMock()], + page: 1, + per_page: 1, + total: 1, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.test.ts new file mode 100644 index 0000000000000..18d96785ad2eb --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.test.ts @@ -0,0 +1,152 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getFoundExceptionListSchemaMock } from './index.mock'; +import { FoundExceptionListSchema, foundExceptionListSchema } from '.'; +import { getExceptionListSchemaMock } from '../exception_list_schema/index.mock'; +import { ExceptionListSchema } from '../exception_list_schema'; + +describe('exception_list_schema', () => { + test('it should validate a typical exception list response', () => { + const payload = getFoundExceptionListSchemaMock(); + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept a malformed exception list item within "data"', () => { + const item: Omit & { + entries?: string[]; + } = { ...getExceptionListSchemaMock(), entries: ['I should not be here'] }; + const payload: Omit & { + data?: Array< + Omit & { + entries?: string[]; + } + >; + } = { ...getFoundExceptionListSchemaMock(), data: [item] }; + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'invalid keys "entries,["I should not be here"]"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept a string for "page"', () => { + const payload: Omit & { + page?: string; + } = { ...getFoundExceptionListSchemaMock(), page: '1' }; + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "page"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept a string for "per_page"', () => { + const payload: Omit & { + per_page?: string; + } = { ...getFoundExceptionListSchemaMock(), per_page: '20' }; + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "20" supplied to "per_page"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept a string for "total"', () => { + const payload: Omit & { + total?: string; + } = { ...getFoundExceptionListSchemaMock(), total: '1' }; + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "total"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "page"', () => { + const payload = getFoundExceptionListSchemaMock(); + // @ts-expect-error + delete payload.page; + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "page"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "per_page"', () => { + const payload = getFoundExceptionListSchemaMock(); + // @ts-expect-error + delete payload.per_page; + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "per_page"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "total"', () => { + const payload = getFoundExceptionListSchemaMock(); + // @ts-expect-error + delete payload.total; + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "total"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "data"', () => { + const payload = getFoundExceptionListSchemaMock(); + // @ts-expect-error + delete payload.data; + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "data"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: FoundExceptionListSchema & { + extraKey?: string; + } = getFoundExceptionListSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = foundExceptionListSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.ts new file mode 100644 index 0000000000000..cb7867db7f295 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_exception_list_schema/index.ts @@ -0,0 +1,29 @@ +/* + * 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 * as t from 'io-ts'; + +import { page } from '../../common/page'; +import { per_page } from '../../common/per_page'; +import { pitId } from '../../common/pit'; +import { total } from '../../common/total'; + +import { exceptionListSchema } from '../exception_list_schema'; + +export const foundExceptionListSchema = t.intersection([ + t.exact( + t.type({ + data: t.array(exceptionListSchema), + page, + per_page, + total, + }) + ), + t.exact(t.partial({ pit: pitId })), +]); + +export type FoundExceptionListSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..bc6c6b63dbea5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.mock.ts @@ -0,0 +1,17 @@ +/* + * 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 { FoundListItemSchema } from '.'; +import { getListItemResponseMock } from '../list_item_schema/index.mock'; + +export const getFoundListItemSchemaMock = (): FoundListItemSchema => ({ + cursor: 'WzI1LFsiNmE3NmI2OWQtODBkZi00YWIyLThjM2UtODVmNDY2YjA2YTBlIl1d', + data: [getListItemResponseMock()], + page: 1, + per_page: 25, + total: 1, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.ts new file mode 100644 index 0000000000000..86801ed60bca9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_item_schema/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; + +import { listItemSchema } from '../list_item_schema'; +import { cursor } from '../../common/cursor'; +import { page } from '../../common/page'; +import { per_page } from '../../common/per_page'; +import { total } from '../../common/total'; + +export const foundListItemSchema = t.exact( + t.type({ + cursor, + data: t.array(listItemSchema), + page, + per_page, + total, + }) +); + +export type FoundListItemSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.mock.ts new file mode 100644 index 0000000000000..07cbb1d03000f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.mock.ts @@ -0,0 +1,17 @@ +/* + * 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 { FoundListSchema } from '.'; +import { getListResponseMock } from '../list_schema/index.mock'; + +export const getFoundListSchemaMock = (): FoundListSchema => ({ + cursor: '123', + data: [getListResponseMock()], + page: 1, + per_page: 1, + total: 1, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.ts new file mode 100644 index 0000000000000..16922174e7496 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_list_schema/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; + +import { listSchema } from '../list_schema'; +import { cursor } from '../../common/cursor'; +import { page } from '../../common/page'; +import { per_page } from '../../common/per_page'; +import { total } from '../../common/total'; + +export const foundListSchema = t.exact( + t.type({ + cursor, + data: t.array(listSchema), + page, + per_page, + total, + }) +); + +export type FoundListSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.mock.ts new file mode 100644 index 0000000000000..8d1a421acef2e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FoundListsBySizeSchema } from '.'; +import { getListResponseMock } from '../list_schema/index.mock'; + +export const getFoundListsBySizeSchemaMock = (): FoundListsBySizeSchema => ({ + smallLists: [getListResponseMock()], + largeLists: [getListResponseMock()], +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.ts new file mode 100644 index 0000000000000..0271416b5f3cf --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/found_lists_by_size_schema/index.ts @@ -0,0 +1,19 @@ +/* + * 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 * as t from 'io-ts'; + +import { listSchema } from '../list_schema'; + +export const foundListsBySizeSchema = t.exact( + t.type({ + largeLists: t.array(listSchema), + smallLists: t.array(listSchema), + }) +); + +export type FoundListsBySizeSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.mock.ts new file mode 100644 index 0000000000000..9e8293b382cc5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.mock.ts @@ -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 { ImportExceptionsResponseSchema } from '.'; + +export const getImportExceptionsResponseSchemaMock = ( + success = 0, + lists = 0, + items = 0 +): ImportExceptionsResponseSchema => ({ + errors: [], + success: true, + success_count: success, + success_exception_lists: true, + success_count_exception_lists: lists, + success_exception_list_items: true, + success_count_exception_list_items: items, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.test.ts new file mode 100644 index 0000000000000..d5d481fe87bed --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.test.ts @@ -0,0 +1,128 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { importExceptionsResponseSchema, ImportExceptionsResponseSchema } from '.'; +import { getImportExceptionsResponseSchemaMock } from './index.mock'; + +describe('importExceptionsResponseSchema', () => { + test('it should validate a typical exceptions import response', () => { + const payload = getImportExceptionsResponseSchemaMock(); + const decoded = importExceptionsResponseSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "errors"', () => { + const payload: Partial> = + getImportExceptionsResponseSchemaMock(); + delete payload.errors; + const decoded = importExceptionsResponseSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "errors"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "success"', () => { + const payload: Partial> = + getImportExceptionsResponseSchemaMock(); + delete payload.success; + const decoded = importExceptionsResponseSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "success"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "success_count"', () => { + const payload: Partial> = + getImportExceptionsResponseSchemaMock(); + delete payload.success_count; + const decoded = importExceptionsResponseSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "success_count"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "success_exception_lists"', () => { + const payload: Partial> = + getImportExceptionsResponseSchemaMock(); + delete payload.success_exception_lists; + const decoded = importExceptionsResponseSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "success_exception_lists"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "success_count_exception_lists"', () => { + const payload: Partial> = + getImportExceptionsResponseSchemaMock(); + delete payload.success_count_exception_lists; + const decoded = importExceptionsResponseSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "success_count_exception_lists"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "success_exception_list_items"', () => { + const payload: Partial> = + getImportExceptionsResponseSchemaMock(); + delete payload.success_exception_list_items; + const decoded = importExceptionsResponseSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "success_exception_list_items"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "success_count_exception_list_items"', () => { + const payload: Partial> = + getImportExceptionsResponseSchemaMock(); + delete payload.success_count_exception_list_items; + const decoded = importExceptionsResponseSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "success_count_exception_list_items"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ImportExceptionsResponseSchema & { + extraKey?: string; + } = getImportExceptionsResponseSchemaMock(); + payload.extraKey = 'some new value'; + const decoded = importExceptionsResponseSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.ts new file mode 100644 index 0000000000000..4a172d2ec10a7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/import_exceptions_schema/index.ts @@ -0,0 +1,50 @@ +/* + * 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 * as t from 'io-ts'; + +import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; + +import { id } from '../../common/id'; +import { list_id } from '../../common/list_id'; +import { item_id } from '../../common/item_id'; + +export const bulkErrorErrorSchema = t.exact( + t.type({ + status_code: t.number, + message: t.string, + }) +); + +export const bulkErrorSchema = t.intersection([ + t.exact( + t.type({ + error: bulkErrorErrorSchema, + }) + ), + t.partial({ + id, + list_id, + item_id, + }), +]); + +export type BulkErrorSchema = t.TypeOf; + +export const importExceptionsResponseSchema = t.exact( + t.type({ + errors: t.array(bulkErrorSchema), + success: t.boolean, + success_count: PositiveInteger, + success_exception_lists: t.boolean, + success_count_exception_lists: PositiveInteger, + success_exception_list_items: t.boolean, + success_count_exception_list_items: PositiveInteger, + }) +); + +export type ImportExceptionsResponseSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts new file mode 100644 index 0000000000000..04b00f43c7029 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/index.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +export * from './acknowledge_schema'; +export * from './create_endpoint_list_schema'; +export * from './exception_list_schema'; +export * from './exception_list_item_schema'; +export * from './found_exception_list_item_schema'; +export * from './found_exception_list_schema'; +export * from './found_all_list_items_schema'; +export * from './found_lists_by_size_schema'; +export * from './found_list_item_schema'; +export * from './found_list_schema'; +export * from './import_exceptions_schema'; +export * from './list_item_schema'; +export * from './list_schema'; +export * from './exception_list_summary_schema'; +export * from './list_item_index_exist_schema'; +export * from './search_list_item_schema'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.mock.ts new file mode 100644 index 0000000000000..b3416ab76852e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ListItemIndexExistSchema } from '.'; + +export const getListItemIndexExistSchemaResponseMock = (): ListItemIndexExistSchema => ({ + list_index: true, + list_item_index: true, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.test.ts new file mode 100644 index 0000000000000..0c8812795935e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.test.ts @@ -0,0 +1,65 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getListItemIndexExistSchemaResponseMock } from './index.mock'; +import { ListItemIndexExistSchema, listItemIndexExistSchema } from '.'; + +describe('list_item_index_exist_schema', () => { + test('it should validate a typical list item request', () => { + const payload = getListItemIndexExistSchemaResponseMock(); + const decoded = listItemIndexExistSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "list_index"', () => { + const payload = getListItemIndexExistSchemaResponseMock(); + // @ts-expect-error + delete payload.list_index; + const decoded = listItemIndexExistSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_index"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "list_item_index"', () => { + const payload = getListItemIndexExistSchemaResponseMock(); + // @ts-expect-error + delete payload.list_item_index; + const decoded = listItemIndexExistSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_item_index"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ListItemIndexExistSchema & { + extraKey?: string; + } = getListItemIndexExistSchemaResponseMock(); + payload.extraKey = 'some new value'; + const decoded = listItemIndexExistSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.ts new file mode 100644 index 0000000000000..fb1070f72daea --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_index_exist_schema/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * as t from 'io-ts'; + +export const listItemIndexExistSchema = t.exact( + t.type({ + list_index: t.boolean, + list_item_index: t.boolean, + }) +); + +export type ListItemIndexExistSchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..10283965276d2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.mock.ts @@ -0,0 +1,48 @@ +/* + * 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 { ListItemSchema } from '.'; +import { + DATE_NOW, + ELASTIC_USER, + LIST_ID, + LIST_ITEM_ID, + META, + TIE_BREAKER, + TYPE, + USER, + VALUE, +} from '../../constants/index.mock'; + +export const getListItemResponseMock = (): ListItemSchema => ({ + _version: undefined, + '@timestamp': DATE_NOW, + created_at: DATE_NOW, + created_by: USER, + deserializer: undefined, + id: LIST_ITEM_ID, + list_id: LIST_ID, + meta: META, + serializer: undefined, + tie_breaker_id: TIE_BREAKER, + type: TYPE, + updated_at: DATE_NOW, + updated_by: USER, + value: VALUE, +}); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getListItemResponseMockWithoutAutoGeneratedValues = (): Partial => ({ + created_by: ELASTIC_USER, + list_id: LIST_ID, + type: TYPE, + updated_by: ELASTIC_USER, + value: VALUE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.test.ts new file mode 100644 index 0000000000000..f855448ff26ef --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.test.ts @@ -0,0 +1,192 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getListItemResponseMock } from './index.mock'; +import { ListItemSchema, listItemSchema } from '.'; + +describe('list_item_schema', () => { + test('it should validate a typical list item response', () => { + const payload = getListItemResponseMock(); + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "id"', () => { + const payload = getListItemResponseMock(); + // @ts-expect-error + delete payload.id; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "list_id"', () => { + const payload = getListItemResponseMock(); + // @ts-expect-error + delete payload.list_id; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "list_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "meta"', () => { + const payload = getListItemResponseMock(); + delete payload.meta; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "serializer"', () => { + const payload = getListItemResponseMock(); + delete payload.serializer; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "deserializer"', () => { + const payload = getListItemResponseMock(); + delete payload.deserializer; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "created_at"', () => { + const payload = getListItemResponseMock(); + // @ts-expect-error + delete payload.created_at; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "created_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "created_by"', () => { + const payload = getListItemResponseMock(); + // @ts-expect-error + delete payload.created_by; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "created_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "tie_breaker_id"', () => { + const payload = getListItemResponseMock(); + // @ts-expect-error + delete payload.tie_breaker_id; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "tie_breaker_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "type"', () => { + const payload = getListItemResponseMock(); + // @ts-expect-error + delete payload.type; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "updated_at"', () => { + const payload = getListItemResponseMock(); + // @ts-expect-error + delete payload.updated_at; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "updated_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "updated_by"', () => { + const payload = getListItemResponseMock(); + // @ts-expect-error + delete payload.updated_by; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "updated_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "value"', () => { + const payload = getListItemResponseMock(); + // @ts-expect-error + delete payload.value; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "value"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ListItemSchema & { extraKey?: string } = getListItemResponseMock(); + payload.extraKey = 'some new value'; + const decoded = listItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.ts new file mode 100644 index 0000000000000..0e7af6ab27267 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_item_schema/index.ts @@ -0,0 +1,47 @@ +/* + * 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 * as t from 'io-ts'; + +import { _versionOrUndefined } from '../../common/underscore_version'; +import { deserializerOrUndefined } from '../../common/deserializer'; +import { metaOrUndefined } from '../../common/meta'; +import { timestampOrUndefined } from '../../common/timestamp'; +import { serializerOrUndefined } from '../../common/serializer'; +import { created_at } from '../../common/created_at'; +import { created_by } from '../../common/created_by'; +import { id } from '../../common/id'; +import { tie_breaker_id } from '../../common/tie_breaker_id'; +import { type } from '../../common/type'; +import { updated_at } from '../../common/updated_at'; +import { updated_by } from '../../common/updated_by'; +import { list_id } from '../../common/list_id'; +import { value } from '../../common/value'; + +export const listItemSchema = t.exact( + t.type({ + _version: _versionOrUndefined, + '@timestamp': timestampOrUndefined, + created_at, + created_by, + deserializer: deserializerOrUndefined, + id, + list_id, + meta: metaOrUndefined, + serializer: serializerOrUndefined, + tie_breaker_id, + type, + updated_at, + updated_by, + value, + }) +); + +export type ListItemSchema = t.TypeOf; + +export const listItemArraySchema = t.array(listItemSchema); +export type ListItemArraySchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.mock.ts new file mode 100644 index 0000000000000..3b6ff22ceb155 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.mock.ts @@ -0,0 +1,54 @@ +/* + * 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 { ListSchema } from '.'; +import { + DATE_NOW, + DESCRIPTION, + ELASTIC_USER, + IMMUTABLE, + LIST_ID, + META, + NAME, + TIE_BREAKER, + TYPE, + USER, + VERSION, +} from '../../constants/index.mock'; + +export const getListResponseMock = (): ListSchema => ({ + _version: undefined, + '@timestamp': DATE_NOW, + created_at: DATE_NOW, + created_by: USER, + description: DESCRIPTION, + deserializer: undefined, + id: LIST_ID, + immutable: IMMUTABLE, + meta: META, + name: NAME, + serializer: undefined, + tie_breaker_id: TIE_BREAKER, + type: TYPE, + updated_at: DATE_NOW, + updated_by: USER, + version: VERSION, +}); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getListResponseMockWithoutAutoGeneratedValues = (): Partial => ({ + created_by: ELASTIC_USER, + description: DESCRIPTION, + immutable: IMMUTABLE, + name: NAME, + type: TYPE, + updated_by: ELASTIC_USER, + version: VERSION, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.test.ts new file mode 100644 index 0000000000000..920941a2135a8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.test.ts @@ -0,0 +1,192 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getListResponseMock } from './index.mock'; +import { ListSchema, listSchema } from '.'; + +describe('list_schema', () => { + test('it should validate a typical list response', () => { + const payload = getListResponseMock(); + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "id"', () => { + const payload = getListResponseMock(); + // @ts-expect-error + delete payload.id; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual(['Invalid value "undefined" supplied to "id"']); + expect(message.schema).toEqual({}); + }); + + test('it should accept an undefined for "meta"', () => { + const payload = getListResponseMock(); + delete payload.meta; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "serializer"', () => { + const payload = getListResponseMock(); + delete payload.serializer; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should accept an undefined for "deserializer"', () => { + const payload = getListResponseMock(); + delete payload.deserializer; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT accept an undefined for "created_at"', () => { + const payload = getListResponseMock(); + // @ts-expect-error + delete payload.created_at; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "created_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "created_by"', () => { + const payload = getListResponseMock(); + // @ts-expect-error + delete payload.created_by; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "created_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "tie_breaker_id"', () => { + const payload = getListResponseMock(); + // @ts-expect-error + delete payload.tie_breaker_id; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "tie_breaker_id"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "type"', () => { + const payload = getListResponseMock(); + // @ts-expect-error + delete payload.type; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "type"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "updated_at"', () => { + const payload = getListResponseMock(); + // @ts-expect-error + delete payload.updated_at; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "updated_at"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "updated_by"', () => { + const payload = getListResponseMock(); + // @ts-expect-error + delete payload.updated_by; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "updated_by"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "name"', () => { + const payload = getListResponseMock(); + // @ts-expect-error + delete payload.name; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "name"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should NOT accept an undefined for "description"', () => { + const payload = getListResponseMock(); + // @ts-expect-error + delete payload.description; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "description"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: ListSchema & { extraKey?: string } = getListResponseMock(); + payload.extraKey = 'some new value'; + const decoded = listSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.ts new file mode 100644 index 0000000000000..687c93ad6f6d0 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/list_schema/index.ts @@ -0,0 +1,50 @@ +/* + * 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 * as t from 'io-ts'; +import { version } from '@kbn/securitysolution-io-ts-types'; +import { _versionOrUndefined } from '../../common/underscore_version'; +import { deserializerOrUndefined } from '../../common/deserializer'; +import { metaOrUndefined } from '../../common/meta'; +import { serializerOrUndefined } from '../../common/serializer'; +import { created_at } from '../../common/created_at'; +import { timestampOrUndefined } from '../../common/timestamp'; +import { created_by } from '../../common/created_by'; +import { description } from '../../common/description'; +import { id } from '../../common/id'; +import { immutable } from '../../common/immutable'; +import { name } from '../../common/name'; +import { tie_breaker_id } from '../../common/tie_breaker_id'; +import { type } from '../../common/type'; +import { updated_at } from '../../common/updated_at'; +import { updated_by } from '../../common/updated_by'; + +export const listSchema = t.exact( + t.type({ + _version: _versionOrUndefined, + '@timestamp': timestampOrUndefined, + created_at, + created_by, + description, + deserializer: deserializerOrUndefined, + id, + immutable, + meta: metaOrUndefined, + name, + serializer: serializerOrUndefined, + tie_breaker_id, + type, + updated_at, + updated_by, + version, + }) +); + +export type ListSchema = t.TypeOf; + +export const listArraySchema = t.array(listSchema); +export type ListArraySchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.mock.ts new file mode 100644 index 0000000000000..1ce8e23d4af5b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SearchListItemSchema } from '.'; +import { VALUE } from '../../constants/index.mock'; +import { getListItemResponseMock } from '../list_item_schema/index.mock'; + +export const getSearchListItemResponseMock = (): SearchListItemSchema => ({ + items: [getListItemResponseMock()], + value: VALUE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.test.ts new file mode 100644 index 0000000000000..6f89a58e0bc3d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.test.ts @@ -0,0 +1,47 @@ +/* + * 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 { left } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; + +import { getSearchListItemResponseMock } from './index.mock'; +import { SearchListItemSchema, searchListItemSchema } from '.'; + +describe('search_list_item_schema', () => { + test('it should validate a typical search list item response', () => { + const payload = getSearchListItemResponseMock(); + const decoded = searchListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([]); + expect(message.schema).toEqual(payload); + }); + + test('it should NOT validate with an "undefined" for "items"', () => { + const { items, ...noItems } = getSearchListItemResponseMock(); + const decoded = searchListItemSchema.decode(noItems); + const checked = exactCheck(noItems, decoded); + const message = pipe(checked, foldLeftRight); + + expect(getPaths(left(message.errors))).toEqual([ + 'Invalid value "undefined" supplied to "items"', + ]); + expect(message.schema).toEqual({}); + }); + + test('it should not allow an extra key to be sent in', () => { + const payload: SearchListItemSchema & { extraKey?: string } = getSearchListItemResponseMock(); + payload.extraKey = 'some new value'; + const decoded = searchListItemSchema.decode(payload); + const checked = exactCheck(payload, decoded); + const message = pipe(checked, foldLeftRight); + expect(getPaths(left(message.errors))).toEqual(['invalid keys "extraKey"']); + expect(message.schema).toEqual({}); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.ts new file mode 100644 index 0000000000000..8c17db0765005 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/response/search_list_item_schema/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * as t from 'io-ts'; +import { listItemArraySchema } from '../list_item_schema'; + +/** + * NOTE: Although this is defined within "response" this does not expose a REST API + * endpoint right now for this particular response. Instead this is only used internally + * for the plugins at this moment. If this changes, please remove this message. + */ +export const searchListItemSchema = t.exact( + t.type({ + items: listItemArraySchema, + value: t.unknown, + }) +); + +export type SearchListItemSchema = t.TypeOf; + +export const searchListItemArraySchema = t.array(searchListItemSchema); +export type SearchListItemArraySchema = t.TypeOf; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts new file mode 100644 index 0000000000000..8b172753bbc5b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/src/typescript_types/index.ts @@ -0,0 +1,242 @@ +/* + * 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 type { HttpStart } from '@kbn/core-http-browser'; +import type { NotificationsStart } from '@kbn/core-notifications-browser'; +import type { Filter } from '@kbn/es-query'; +import { NamespaceType } from '../common/default_namespace'; +import { ExceptionListType, ExceptionListTypeEnum } from '../common/exception_list'; +import { Page } from '../common/page'; +import { PerPage } from '../common/per_page'; +import { TotalOrUndefined } from '../common/total'; +import { CreateExceptionListItemSchema } from '../request/create_exception_list_item_schema'; +import { CreateExceptionListSchema } from '../request/create_exception_list_schema'; +import { ExceptionListId } from '../request/get_exception_filter_schema'; +import { UpdateExceptionListItemSchema } from '../request/update_exception_list_item_schema'; +import { UpdateExceptionListSchema } from '../request/update_exception_list_schema'; +import { ExceptionListItemSchema } from '../response/exception_list_item_schema'; +import { ExceptionListSchema } from '../response/exception_list_schema'; + +interface BaseParams { + http: HttpStart; + signal: AbortSignal; +} + +export interface DuplicateExceptionListProps extends BaseParams { + listId: string; + namespaceType: NamespaceType; + includeExpiredExceptions: boolean; +} + +export interface ApiListDuplicateProps + extends Omit { + onError: (err: Error) => void; + onSuccess: (newList: ExceptionListSchema) => void; +} + +export interface ExceptionListFilter { + name?: string | null; + list_id?: string | null; + created_by?: string | null; + types?: ExceptionListTypeEnum[] | null; + tags?: string | null; +} + +export interface UseExceptionListsProps { + errorMessage: string; + filterOptions?: ExceptionListFilter; + http: HttpStart; + namespaceTypes: NamespaceType[]; + notifications: NotificationsStart; + initialPagination?: Pagination; + hideLists?: readonly string[]; + initialSort?: Sort; +} + +export interface UseExceptionListProps { + http: HttpStart; + lists: ExceptionListIdentifiers[]; + onError?: (arg: string[]) => void; + filterOptions: FilterExceptionsOptions[]; + pagination?: Pagination; + showDetectionsListsOnly: boolean; + showEndpointListsOnly: boolean; + matchFilters: boolean; + onSuccess?: (arg: UseExceptionListItemsSuccess) => void; + sort?: Sort; +} + +export interface FilterExceptionsOptions { + filter: string; + tags: string[]; +} + +export interface ApiCallMemoProps { + id: string; + namespaceType: NamespaceType; + onError: (arg: Error) => void; + onSuccess: () => void; +} + +// TODO: Switch to use ApiCallMemoProps +// after cleaning up exceptions/api file to +// remove unnecessary validation checks +export interface ApiListExportProps { + id: string; + includeExpiredExceptions: boolean; + listId: string; + namespaceType: NamespaceType; + onError: (err: Error) => void; + onSuccess: (blob: Blob) => void; +} + +export interface Sort { + field: string; + order: string; +} +export interface Pagination { + page: Page; + perPage: PerPage; + total: TotalOrUndefined; +} + +export interface UseExceptionListItemsSuccess { + exceptions: ExceptionListItemSchema[]; + pagination: Pagination; +} + +export interface ExceptionListIdentifiers { + id: string; + listId: string; + namespaceType: NamespaceType; + type: ExceptionListType; +} + +export interface ApiCallFindListsItemsMemoProps { + lists: ExceptionListIdentifiers[]; + pagination: Partial; + showDetectionsListsOnly: boolean; + showEndpointListsOnly: boolean; + filter?: string; + onError: (arg: string[]) => void; + onSuccess: (arg: UseExceptionListItemsSuccess) => void; +} + +export interface ApiCallGetExceptionFilterFromIdsMemoProps extends GetExceptionFilterOptionalProps { + exceptionListIds: ExceptionListId[]; + onError: (arg: string[]) => void; + onSuccess: (arg: Filter) => void; +} + +export interface ApiCallGetExceptionFilterFromExceptionsMemoProps + extends GetExceptionFilterOptionalProps { + exceptions: Array; + onError: (arg: string[]) => void; + onSuccess: (arg: Filter) => void; +} + +export interface ExportExceptionListProps { + http: HttpStart; + id: string; + listId: string; + namespaceType: NamespaceType; + includeExpiredExceptions: boolean; + signal: AbortSignal; +} + +export interface AddEndpointExceptionListProps { + http: HttpStart; + signal: AbortSignal; +} + +export interface UpdateExceptionListItemProps { + http: HttpStart; + listItem: UpdateExceptionListItemSchema; + signal: AbortSignal; +} + +export interface UpdateExceptionListProps { + http: HttpStart; + list: UpdateExceptionListSchema; + signal: AbortSignal; +} + +export interface AddExceptionListItemProps { + http: HttpStart; + listItem: CreateExceptionListItemSchema; + signal: AbortSignal; +} + +export interface AddExceptionListProps { + http: HttpStart; + list: CreateExceptionListSchema; + signal: AbortSignal; +} + +export interface UseExceptionListsSuccess { + exceptions: ExceptionListSchema[]; + pagination: Pagination; +} + +export interface ApiCallFetchExceptionListsProps { + http: HttpStart; + namespaceTypes: string; + pagination: Partial; + sort?: Sort; + filters: string; + signal: AbortSignal; +} + +export interface ApiCallByIdProps { + http: HttpStart; + id: string; + namespaceType: NamespaceType; + signal: AbortSignal; +} + +export interface ApiCallByListIdProps { + http: HttpStart; + listIds: string[]; + namespaceTypes: NamespaceType[]; + pagination: Partial; + search?: string; + filter?: string; + signal: AbortSignal; +} + +export type AddExceptionList = UpdateExceptionListSchema | CreateExceptionListSchema; + +export interface PersistHookProps { + http: HttpStart; + onError: (arg: Error) => void; +} + +export interface ExceptionList extends ExceptionListSchema { + totalItems: number; +} + +export interface GetExceptionFilterOptionalProps { + signal?: AbortSignal; + chunkSize?: number; + alias?: string; + excludeExceptions?: boolean; +} + +export interface GetExceptionFilterFromExceptionListIdsProps + extends GetExceptionFilterOptionalProps { + http: HttpStart; + exceptionListIds: ExceptionListId[]; +} + +export interface GetExceptionFilterFromExceptionsProps extends GetExceptionFilterOptionalProps { + http: HttpStart; + exceptions: Array; +} + +export interface ExceptionFilterResponse { + filter: Filter; +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/tsconfig.json new file mode 100644 index 0000000000000..b8097b0b7b12d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "include": ["**/*.ts"], + "kbn_references": [ + "@kbn/securitysolution-io-ts-types", + "@kbn/securitysolution-io-ts-utils", + "@kbn/securitysolution-list-constants", + "@kbn/es-query", + "@kbn/core-http-browser", + "@kbn/core-notifications-browser", + "@kbn/securitysolution-exceptions-common" + ], + "exclude": ["target/**/*"] +} diff --git a/packages/kbn-securitysolution-list-api/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/README.md similarity index 100% rename from packages/kbn-securitysolution-list-api/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-list-api/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/index.ts new file mode 100644 index 0000000000000..afe1280b9b856 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +export * from './src/api'; +export * from './src/fp_utils'; +export * from './src/list_api'; +export * from './src/list_item_api'; +export * from './src/types'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/jest.config.js b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/jest.config.js new file mode 100644 index 0000000000000..9e9844e5cbd01 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/solutions/security/packages/kbn-securitysolution-list-api'], +}; diff --git a/packages/kbn-securitysolution-list-api/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-list-api/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-list-api/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/package.json new file mode 100644 index 0000000000000..5159b04f62049 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/securitysolution-list-api", + "version": "1.0.0", + "description": "security solution list REST API", + "license": "Elastic License 2.0", + "private": true +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/api/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/api/index.ts new file mode 100644 index 0000000000000..c8fe4143d1bdb --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/api/index.ts @@ -0,0 +1,664 @@ +/* + * 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 { 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, + GetExceptionFilterFromExceptionListIdsProps, + GetExceptionFilterFromExceptionsProps, + ExceptionFilterResponse, + DuplicateExceptionListProps, +} from '@kbn/securitysolution-io-ts-list-types'; + +import { + ENDPOINT_LIST_URL, + INTERNAL_EXCEPTION_FILTER, + EXCEPTION_LIST_ITEM_URL, + EXCEPTION_LIST_URL, +} from '@kbn/securitysolution-list-constants'; +import { toError, toPromise } from '../fp_utils'; + +const version = '2023-10-31'; + +/** + * 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 => + http.fetch(EXCEPTION_LIST_URL, { + body: JSON.stringify(list), + method: 'POST', + signal, + version, + }); + +const addExceptionListWithValidation = async ({ + http, + list, + signal, +}: AddExceptionListProps): Promise => + 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 => + http.fetch(EXCEPTION_LIST_ITEM_URL, { + body: JSON.stringify(listItem), + method: 'POST', + signal, + version, + }); + +const addExceptionListItemWithValidation = async ({ + http, + listItem, + signal, +}: AddExceptionListItemProps): Promise => + 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 => + http.fetch(EXCEPTION_LIST_URL, { + body: JSON.stringify(list), + method: 'PUT', + signal, + version, + }); + +const updateExceptionListWithValidation = async ({ + http, + list, + signal, +}: UpdateExceptionListProps): Promise => + 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 => + http.fetch(EXCEPTION_LIST_ITEM_URL, { + body: JSON.stringify(listItem), + method: 'PUT', + signal, + version, + }); + +const updateExceptionListItemWithValidation = async ({ + http, + listItem, + signal, +}: UpdateExceptionListItemProps): Promise => + 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, + sort, +}: ApiCallFetchExceptionListsProps): Promise => { + const query = { + filter: filters || undefined, + namespace_type: namespaceTypes, + page: pagination.page ? `${pagination.page}` : '1', + per_page: pagination.perPage ? `${pagination.perPage}` : '20', + sort_field: sort?.field ? sort?.field : 'exception-list.created_at', + sort_order: sort?.order ? sort?.order : 'desc', + }; + + return http.fetch(`${EXCEPTION_LIST_URL}/_find`, { + method: 'GET', + query, + signal, + version, + }); +}; + +const fetchExceptionListsWithValidation = async ({ + filters, + http, + namespaceTypes, + pagination, + signal, + sort, +}: ApiCallFetchExceptionListsProps): Promise => + flow( + () => + tryCatch( + () => + fetchExceptionLists({ + filters, + http, + namespaceTypes, + pagination, + signal, + sort, + }), + 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 => + http.fetch(EXCEPTION_LIST_URL, { + method: 'GET', + query: { id, namespace_type: namespaceType }, + signal, + version, + }); + +const fetchExceptionListByIdWithValidation = async ({ + http, + id, + namespaceType, + signal, +}: ApiCallByIdProps): Promise => + 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 search optional - simple search string + * @param filter optional + * @param pagination optional + * @param signal to cancel request + * + * @throws An error if response is not OK + */ +const fetchExceptionListsItemsByListIds = async ({ + http, + listIds, + namespaceTypes, + filter, + pagination, + search, + signal, +}: ApiCallByListIdProps): Promise => { + const query = { + list_id: listIds.join(','), + namespace_type: namespaceTypes.join(','), + page: pagination.page ? `${pagination.page}` : '1', + per_page: pagination.perPage ? `${pagination.perPage}` : '20', + search, + sort_field: 'exception-list.created_at', + sort_order: 'desc', + filter, + }; + + return http.fetch(`${EXCEPTION_LIST_ITEM_URL}/_find`, { + method: 'GET', + query, + signal, + version, + }); +}; + +const fetchExceptionListsItemsByListIdsWithValidation = async ({ + filter, + http, + listIds, + namespaceTypes, + pagination, + search, + signal, +}: ApiCallByListIdProps): Promise => + flow( + () => + tryCatch( + () => + fetchExceptionListsItemsByListIds({ + filter, + http, + listIds, + namespaceTypes, + pagination, + search, + 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 => + http.fetch(EXCEPTION_LIST_ITEM_URL, { + method: 'GET', + query: { id, namespace_type: namespaceType }, + signal, + version, + }); + +const fetchExceptionListItemByIdWithValidation = async ({ + http, + id, + namespaceType, + signal, +}: ApiCallByIdProps): Promise => + 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 => + http.fetch(EXCEPTION_LIST_URL, { + method: 'DELETE', + query: { id, namespace_type: namespaceType }, + signal, + version, + }); + +const deleteExceptionListByIdWithValidation = async ({ + http, + id, + namespaceType, + signal, +}: ApiCallByIdProps): Promise => + 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 => + http.fetch(EXCEPTION_LIST_ITEM_URL, { + method: 'DELETE', + query: { id, namespace_type: namespaceType }, + signal, + version, + }); + +const deleteExceptionListItemByIdWithValidation = async ({ + http, + id, + namespaceType, + signal, +}: ApiCallByIdProps): Promise => + 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 => + http.fetch(ENDPOINT_LIST_URL, { + method: 'POST', + signal, + version, + }); + +const addEndpointExceptionListWithValidation = async ({ + http, + signal, +}: AddEndpointExceptionListProps): Promise => + flow( + () => tryCatch(() => addEndpointExceptionList({ http, signal }), toError), + chain((response) => fromEither(validateEither(createEndpointListSchema, response))), + flow(toPromise) + )(); + +export { addEndpointExceptionListWithValidation as addEndpointExceptionList }; + +/** + * Export an ExceptionList by providing a ExceptionList ID + * + * @param http Kibana http service + * @param id ExceptionList ID (not list_id) + * @param includeExpiredExceptions boolean for including expired exceptions + * @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, + includeExpiredExceptions, + listId, + namespaceType, + signal, +}: ExportExceptionListProps): Promise => + http.fetch(`${EXCEPTION_LIST_URL}/_export`, { + method: 'POST', + query: { + id, + list_id: listId, + namespace_type: namespaceType, + include_expired_exceptions: includeExpiredExceptions, + }, + signal, + version, + }); + +/** + * Create a Filter query from an exception list id + * + * @param exceptionListId The id of the exception list from which create a Filter query + * @param signal AbortSignal for cancelling request + * + * @throws An error if response is not OK + */ +export const getExceptionFilterFromExceptionListIds = async ({ + alias, + chunkSize, + exceptionListIds, + excludeExceptions, + http, + signal, +}: GetExceptionFilterFromExceptionListIdsProps): Promise => + http.fetch(INTERNAL_EXCEPTION_FILTER, { + method: 'POST', + version: '1', + body: JSON.stringify({ + exception_list_ids: exceptionListIds, + type: 'exception_list_ids', + alias, + exclude_exceptions: excludeExceptions, + chunk_size: chunkSize, + }), + signal, + }); + +/** + * Create a Filter query from a list of exceptions + * + * @param exceptions Exception items to be made into a `Filter` query + * @param signal AbortSignal for cancelling request + * + * @throws An error if response is not OK + */ +export const getExceptionFilterFromExceptions = async ({ + exceptions, + alias, + excludeExceptions, + http, + chunkSize, + signal, +}: GetExceptionFilterFromExceptionsProps): Promise => + http.fetch(INTERNAL_EXCEPTION_FILTER, { + method: 'POST', + version: '1', + body: JSON.stringify({ + exceptions, + type: 'exception_items', + alias, + exclude_exceptions: excludeExceptions, + chunk_size: chunkSize, + }), + signal, + }); + +/** + * Duplicate an ExceptionList and its items by providing a ExceptionList list_id + * + * @param http Kibana http service + * @param includeExpiredExceptions boolean for including exception items with expired TTL + * @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 duplicateExceptionList = async ({ + http, + includeExpiredExceptions, + listId, + namespaceType, + signal, +}: DuplicateExceptionListProps): Promise => + http.fetch(`${EXCEPTION_LIST_URL}/_duplicate`, { + method: 'POST', + query: { + list_id: listId, + namespace_type: namespaceType, + include_expired_exceptions: includeExpiredExceptions, + }, + signal, + version, + }); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/fp_utils/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/fp_utils/index.test.ts new file mode 100644 index 0000000000000..574c0f97292ef --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/fp_utils/index.test.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +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'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/fp_utils/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/fp_utils/index.ts new file mode 100644 index 0000000000000..1360c78db59ef --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/fp_utils/index.ts @@ -0,0 +1,23 @@ +/* + * 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 { 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 (taskEither: TaskEither): Promise => + 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))); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/index.test.ts new file mode 100644 index 0000000000000..1168b4e491951 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/index.test.ts @@ -0,0 +1,443 @@ +/* + * 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 { createListIndex, deleteList, exportList, findLists, importList, readListIndex } from '.'; +import { + ApiPayload, + DeleteListParams, + ExportListParams, + FindListsParams, + ImportListParams, +} from '../types'; + +import { HttpFetchOptions } from '@kbn/core-http-browser'; +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; + +import { getFoundListSchemaMock } from './mocks/response/found_list_schema.mock'; +import { getListResponseMock } from './mocks/response/list_schema.mock'; +import { getListItemIndexExistSchemaResponseMock } from './mocks/response/list_item_index_exist_schema.mock'; +import { getAcknowledgeSchemaResponseMock } from './mocks/response/acknowledge_schema.mock'; + +describe('Value Lists API', () => { + let httpMock: ReturnType; + + beforeEach(() => { + httpMock = httpServiceMock.createStartContract(); + }); + describe('deleteList', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue(getListResponseMock()); + }); + + it('DELETEs specifying the id as a query parameter', async () => { + const abortCtrl = new AbortController(); + const payload: ApiPayload = { + deleteReferences: false, + id: 'list-id', + ignoreReferences: true, + }; + await deleteList({ + http: httpMock, + ...payload, + signal: abortCtrl.signal, + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists', + expect.objectContaining({ + method: 'DELETE', + query: { deleteReferences: false, id: 'list-id', ignoreReferences: true }, + }) + ); + }); + + it('rejects with an error if request payload is invalid (and does not make API call)', async () => { + const abortCtrl = new AbortController(); + const payload: Omit, 'id'> & { + id: number; + } = { id: 23 }; + + await expect( + deleteList({ + http: httpMock, + ...(payload as unknown as ApiPayload), + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "23" supplied to "id"')); + expect(httpMock.fetch).not.toHaveBeenCalled(); + }); + + it('rejects with an error if response payload is invalid', async () => { + const abortCtrl = new AbortController(); + const payload: ApiPayload = { id: 'list-id' }; + const badResponse = { ...getListResponseMock(), id: undefined }; + httpMock.fetch.mockResolvedValue(badResponse); + + await expect( + deleteList({ + http: httpMock, + ...payload, + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "id"')); + }); + }); + describe('findLists', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue(getFoundListSchemaMock()); + }); + + it('GETs from the lists endpoint', async () => { + const abortCtrl = new AbortController(); + await findLists({ + http: httpMock, + pageIndex: 1, + pageSize: 10, + signal: abortCtrl.signal, + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/_find', + expect.objectContaining({ + method: 'GET', + }) + ); + }); + + it('sends pagination as query parameters', async () => { + const abortCtrl = new AbortController(); + await findLists({ + cursor: 'cursor', + http: httpMock, + pageIndex: 1, + pageSize: 10, + signal: abortCtrl.signal, + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/_find', + expect.objectContaining({ + query: { + cursor: 'cursor', + page: 1, + per_page: 10, + }, + }) + ); + }); + + it('sends sort_field and sort_order as query parameters', async () => { + const abortCtrl = new AbortController(); + await findLists({ + cursor: 'cursor', + http: httpMock, + pageIndex: 1, + pageSize: 10, + signal: abortCtrl.signal, + sortField: 'created_at', + sortOrder: 'desc', + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/_find', + expect.objectContaining({ + query: { + cursor: 'cursor', + page: 1, + per_page: 10, + sort_field: 'created_at', + sort_order: 'desc', + }, + }) + ); + }); + + it('rejects with an error if request payload is invalid (and does not make API call)', async () => { + const abortCtrl = new AbortController(); + const payload: ApiPayload = { + pageIndex: 10, + pageSize: 0, + }; + + await expect( + findLists({ + http: httpMock, + ...payload, + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "0" supplied to "per_page"')); + expect(httpMock.fetch).not.toHaveBeenCalled(); + }); + + it('rejects with an error if response payload is invalid', async () => { + const abortCtrl = new AbortController(); + const payload: ApiPayload = { + pageIndex: 1, + pageSize: 10, + }; + const badResponse = { ...getFoundListSchemaMock(), cursor: undefined }; + httpMock.fetch.mockResolvedValue(badResponse); + + await expect( + findLists({ + http: httpMock, + ...payload, + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "cursor"')); + }); + }); + describe('importList', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue(getListResponseMock()); + }); + + it('POSTs the file', async () => { + const abortCtrl = new AbortController(); + const file = new File([], 'name'); + + await importList({ + file, + http: httpMock, + listId: 'my_list', + signal: abortCtrl.signal, + type: 'keyword', + }); + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/items/_import', + expect.objectContaining({ + method: 'POST', + }) + ); + + // httpmock's fetch signature is inferred incorrectly + const [[, { body }]] = httpMock.fetch.mock.calls as unknown as Array< + [unknown, HttpFetchOptions] + >; + const actualFile = (body as FormData).get('file'); + expect(actualFile).toEqual(file); + }); + + it('sends type and id as query parameters', async () => { + const abortCtrl = new AbortController(); + const file = new File([], 'name'); + + await importList({ + file, + http: httpMock, + listId: 'my_list', + signal: abortCtrl.signal, + type: 'keyword', + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/items/_import', + expect.objectContaining({ + query: { list_id: 'my_list', type: 'keyword' }, + }) + ); + }); + + it('rejects with an error if request body is invalid (and does not make API call)', async () => { + const abortCtrl = new AbortController(); + const payload: ApiPayload = { + file: undefined as unknown as File, + listId: 'list-id', + type: 'ip', + }; + + await expect( + importList({ + http: httpMock, + ...payload, + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "file"')); + expect(httpMock.fetch).not.toHaveBeenCalled(); + }); + + it('rejects with an error if request params are invalid (and does not make API call)', async () => { + const abortCtrl = new AbortController(); + const file = new File([], 'name'); + const payload: ApiPayload = { + file, + listId: 'list-id', + type: 'other' as 'ip', + }; + + await expect( + importList({ + http: httpMock, + ...payload, + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "other" supplied to "type"')); + expect(httpMock.fetch).not.toHaveBeenCalled(); + }); + + it('rejects with an error if response payload is invalid', async () => { + const abortCtrl = new AbortController(); + const file = new File([], 'name'); + const payload: ApiPayload = { + file, + listId: 'list-id', + type: 'ip', + }; + const badResponse = { ...getListResponseMock(), id: undefined }; + httpMock.fetch.mockResolvedValue(badResponse); + + await expect( + importList({ + http: httpMock, + ...payload, + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "id"')); + }); + }); + describe('exportList', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue({}); + }); + + it('POSTs to the export endpoint', async () => { + const abortCtrl = new AbortController(); + + await exportList({ + http: httpMock, + listId: 'my_list', + signal: abortCtrl.signal, + }); + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/items/_export', + expect.objectContaining({ + method: 'POST', + }) + ); + }); + + it('sends type and id as query parameters', async () => { + const abortCtrl = new AbortController(); + + await exportList({ + http: httpMock, + listId: 'my_list', + signal: abortCtrl.signal, + }); + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/items/_export', + expect.objectContaining({ + query: { list_id: 'my_list' }, + }) + ); + }); + + it('rejects with an error if request params are invalid (and does not make API call)', async () => { + const abortCtrl = new AbortController(); + const payload: ApiPayload = { + listId: 23 as unknown as string, + }; + + await expect( + exportList({ + http: httpMock, + ...payload, + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "23" supplied to "list_id"')); + expect(httpMock.fetch).not.toHaveBeenCalled(); + }); + }); + + describe('readListIndex', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue(getListItemIndexExistSchemaResponseMock()); + }); + + it('GETs the list index', async () => { + const abortCtrl = new AbortController(); + await readListIndex({ + http: httpMock, + signal: abortCtrl.signal, + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/index', + expect.objectContaining({ + method: 'GET', + }) + ); + }); + + it('returns the response when valid', async () => { + const abortCtrl = new AbortController(); + const result = await readListIndex({ + http: httpMock, + signal: abortCtrl.signal, + }); + + expect(result).toEqual(getListItemIndexExistSchemaResponseMock()); + }); + + it('rejects with an error if response payload is invalid', async () => { + const abortCtrl = new AbortController(); + const badResponse = { ...getListItemIndexExistSchemaResponseMock(), list_index: undefined }; + httpMock.fetch.mockResolvedValue(badResponse); + + await expect( + readListIndex({ + http: httpMock, + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "list_index"')); + }); + }); + + describe('createListIndex', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue(getAcknowledgeSchemaResponseMock()); + }); + + it('GETs the list index', async () => { + const abortCtrl = new AbortController(); + await createListIndex({ + http: httpMock, + signal: abortCtrl.signal, + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/index', + expect.objectContaining({ + method: 'POST', + }) + ); + }); + + it('returns the response when valid', async () => { + const abortCtrl = new AbortController(); + const result = await createListIndex({ + http: httpMock, + signal: abortCtrl.signal, + }); + + expect(result).toEqual(getAcknowledgeSchemaResponseMock()); + }); + + it('rejects with an error if response payload is invalid', async () => { + const abortCtrl = new AbortController(); + const badResponse = { acknowledged: undefined }; + httpMock.fetch.mockResolvedValue(badResponse); + + await expect( + createListIndex({ + http: httpMock, + signal: abortCtrl.signal, + }) + ).rejects.toEqual(new Error('Invalid value "undefined" supplied to "acknowledged"')); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/index.ts new file mode 100644 index 0000000000000..93160ca739e2e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/index.ts @@ -0,0 +1,342 @@ +/* + * 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 { 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, + ReadListSchema, + acknowledgeSchema, + deleteListSchema, + readListSchema, + exportListItemQuerySchema, + findListSchema, + foundListSchema, + importListItemQuerySchema, + importListItemSchema, + listItemIndexExistSchema, + listSchema, + foundListsBySizeSchema, + FoundListsBySizeSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { + LIST_INDEX, + LIST_ITEM_URL, + LIST_PRIVILEGES_URL, + LIST_URL, + INTERNAL_FIND_LISTS_BY_SIZE, +} from '@kbn/securitysolution-list-constants'; +import { toError, toPromise } from '../fp_utils'; + +import { + ApiParams, + DeleteListParams, + ExportListParams, + FindListsParams, + ImportListParams, + GetListByIdParams, +} from '../types'; + +export type { + ApiParams, + DeleteListParams, + ExportListParams, + FindListsParams, + ImportListParams, +} from '../types'; + +const version = '2023-10-31'; + +const findLists = async ({ + http, + cursor, + page, + // eslint-disable-next-line @typescript-eslint/naming-convention + per_page, + signal, + // eslint-disable-next-line @typescript-eslint/naming-convention + sort_field, + // eslint-disable-next-line @typescript-eslint/naming-convention + sort_order, +}: ApiParams & FindListSchemaEncoded): Promise => { + return http.fetch(`${LIST_URL}/_find`, { + method: 'GET', + query: { + cursor, + page, + per_page, + sort_field, + sort_order, + }, + signal, + version, + }); +}; + +const findListsWithValidation = async ({ + cursor, + http, + pageIndex, + pageSize, + signal, + sortField, + sortOrder, +}: FindListsParams): Promise => + pipe( + { + cursor: cursor != null ? cursor.toString() : undefined, + page: pageIndex != null ? pageIndex.toString() : undefined, + per_page: pageSize != null ? pageSize.toString() : undefined, + sort_field: sortField != null ? sortField.toString() : undefined, + sort_order: sortOrder, + }, + (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 findListsBySize = async ({ + http, + cursor, + page, + // eslint-disable-next-line @typescript-eslint/naming-convention + per_page, + signal, +}: ApiParams & FindListSchemaEncoded): Promise => { + return http.fetch(`${INTERNAL_FIND_LISTS_BY_SIZE}`, { + method: 'GET', + version: '1', + query: { + cursor, + page, + per_page, + }, + signal, + }); +}; + +const findListsBySizeWithValidation = async ({ + cursor, + http, + pageIndex, + pageSize, + signal, +}: FindListsParams): Promise => + 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(() => findListsBySize({ http, signal, ...payload }), toError)), + chain((response) => fromEither(validateEither(foundListsBySizeSchema, response))), + flow(toPromise) + ); + +export { findListsBySizeWithValidation as findListsBySize }; + +const importList = async ({ + file, + http, + // eslint-disable-next-line @typescript-eslint/naming-convention + list_id, + type, + signal, + refresh, +}: ApiParams & + ImportListItemSchemaEncoded & + ImportListItemQuerySchemaEncoded): Promise => { + const formData = new FormData(); + formData.append('file', file as Blob); + + return http.fetch(`${LIST_ITEM_URL}/_import`, { + body: formData, + headers: { 'Content-Type': undefined }, + method: 'POST', + query: { list_id, type, refresh }, + signal, + version, + }); +}; + +const importListWithValidation = async ({ + file, + http, + listId, + type, + signal, + refresh, +}: ImportListParams): Promise => + pipe( + { + list_id: listId, + type, + refresh, + }, + (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 => + http.fetch(LIST_URL, { + method: 'DELETE', + query: { deleteReferences, id, ignoreReferences }, + signal, + version, + }); + +const deleteListWithValidation = async ({ + deleteReferences, + http, + id, + ignoreReferences, + signal, +}: DeleteListParams): Promise => + 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 => + http.fetch(`${LIST_ITEM_URL}/_export`, { + method: 'POST', + query: { list_id }, + signal, + version, + }); + +const exportListWithValidation = async ({ + http, + listId, + signal, +}: ExportListParams): Promise => + 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 => + http.fetch(LIST_INDEX, { + method: 'GET', + signal, + version, + }); + +const readListIndexWithValidation = async ({ + http, + signal, +}: ApiParams): Promise => + 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 => + http.fetch(LIST_PRIVILEGES_URL, { + method: 'GET', + signal, + version, + }); + +const createListIndex = async ({ http, signal }: ApiParams): Promise => + http.fetch(LIST_INDEX, { + method: 'POST', + signal, + version, + }); + +const createListIndexWithValidation = async ({ + http, + signal, +}: ApiParams): Promise => + flow( + () => tryCatch(() => createListIndex({ http, signal }), toError), + chain((response) => fromEither(validateEither(acknowledgeSchema, response))), + flow(toPromise) + )(); + +export { createListIndexWithValidation as createListIndex }; + +const getListById = async ({ + http, + signal, + id, +}: ApiParams & ReadListSchema): Promise => { + return http.fetch(`${LIST_URL}`, { + method: 'GET', + query: { + id, + }, + signal, + version, + }); +}; + +const getListByIdWithValidation = async ({ + http, + signal, + id, +}: GetListByIdParams): Promise => + pipe( + { + id, + }, + (payload) => fromEither(validateEither(readListSchema, payload)), + chain((payload) => tryCatch(() => getListById({ http, signal, ...payload }), toError)), + chain((response) => fromEither(validateEither(listSchema, response))), + flow(toPromise) + ); + +export { getListByIdWithValidation as getListById }; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/constants.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/constants.mock.ts new file mode 100644 index 0000000000000..b3ce62d03f486 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/constants.mock.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export const DATE_NOW = '2020-04-20T15:25:31.830Z'; +export const USER = 'some user'; +export const ELASTIC_USER = 'elastic'; +export const NAME = 'some name'; +export const DESCRIPTION = 'some description'; +export const LIST_ID = 'some-list-id'; +export const TIE_BREAKER = '6a76b69d-80df-4ab2-8c3e-85f466b06a0e'; + +export const META = {}; +export const TYPE = 'ip'; + +export const VERSION = 1; +export const IMMUTABLE = false; diff --git a/x-pack/plugins/lists/common/schemas/response/acknowledge_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/acknowledge_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/acknowledge_schema.mock.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/acknowledge_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/found_list_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/found_list_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/found_list_schema.mock.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/found_list_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/list_item_index_exist_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_item_index_exist_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/list_item_index_exist_schema.mock.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_item_index_exist_schema.mock.ts diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_schema.mock.ts new file mode 100644 index 0000000000000..b2b66ad4636c2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_api/mocks/response/list_schema.mock.ts @@ -0,0 +1,55 @@ +/* + * 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 type { ListSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { + DATE_NOW, + DESCRIPTION, + ELASTIC_USER, + IMMUTABLE, + LIST_ID, + META, + NAME, + TIE_BREAKER, + TYPE, + USER, + VERSION, +} from '../constants.mock'; + +export const getListResponseMock = (): ListSchema => ({ + '@timestamp': DATE_NOW, + _version: undefined, + created_at: DATE_NOW, + created_by: USER, + description: DESCRIPTION, + deserializer: undefined, + id: LIST_ID, + immutable: IMMUTABLE, + meta: META, + name: NAME, + serializer: undefined, + tie_breaker_id: TIE_BREAKER, + type: TYPE, + updated_at: DATE_NOW, + updated_by: USER, + version: VERSION, +}); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getListResponseMockWithoutAutoGeneratedValues = (): Partial => ({ + created_by: ELASTIC_USER, + description: DESCRIPTION, + immutable: IMMUTABLE, + name: NAME, + type: TYPE, + updated_by: ELASTIC_USER, + version: VERSION, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/index.test.ts new file mode 100644 index 0000000000000..651edfe25cb18 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/index.test.ts @@ -0,0 +1,171 @@ +/* + * 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 { createListItem, deleteListItem, findListItems, patchListItem } from '.'; +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; +import { + getFoundListSchemaMock, + getCreateListItemResponseMock, + getUpdatedListItemResponseMock, + getDeletedListItemResponseMock, +} from './mocks/response'; + +describe('Value list item API', () => { + let httpMock: ReturnType; + beforeEach(() => { + httpMock = httpServiceMock.createStartContract(); + }); + + describe('findListItems', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue(getFoundListSchemaMock()); + }); + + it('GETs from the lists endpoint with query params', async () => { + const abortCtrl = new AbortController(); + await findListItems({ + http: httpMock, + pageIndex: 1, + pageSize: 10, + signal: abortCtrl.signal, + filter: '*:*', + listId: 'list_id', + sortField: 'updated_at', + sortOrder: 'asc', + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/items/_find', + expect.objectContaining({ + method: 'GET', + query: { + cursor: undefined, + filter: '*:*', + list_id: 'list_id', + page: 1, + per_page: 10, + sort_field: 'updated_at', + sort_order: 'asc', + }, + }) + ); + }); + }); + + describe('createListItem', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue(getCreateListItemResponseMock()); + }); + + it('POSTs to the lists endpoint with the list item', async () => { + const abortCtrl = new AbortController(); + await createListItem({ + http: httpMock, + signal: abortCtrl.signal, + value: '123', + listId: 'list_id', + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/items', + expect.objectContaining({ + method: 'POST', + body: JSON.stringify({ + value: '123', + list_id: 'list_id', + }), + }) + ); + }); + + it('returns the created list item', async () => { + const abortCtrl = new AbortController(); + const result = await createListItem({ + http: httpMock, + signal: abortCtrl.signal, + value: '123', + listId: 'list_id', + }); + + expect(result).toEqual(getCreateListItemResponseMock()); + }); + }); + + describe('patchListItem', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue(getUpdatedListItemResponseMock()); + }); + + it('PATCH to the lists endpoint with the list item', async () => { + const abortCtrl = new AbortController(); + await patchListItem({ + http: httpMock, + signal: abortCtrl.signal, + id: 'item_id', + value: '123', + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/items', + expect.objectContaining({ + method: 'PATCH', + body: JSON.stringify({ + id: 'item_id', + value: '123', + }), + }) + ); + }); + + it('returns the updated list item', async () => { + const abortCtrl = new AbortController(); + const result = await patchListItem({ + http: httpMock, + signal: abortCtrl.signal, + id: 'item_id', + value: '123', + }); + + expect(result).toEqual(getUpdatedListItemResponseMock()); + }); + }); + + describe('deleteListItem', () => { + beforeEach(() => { + httpMock.fetch.mockResolvedValue(getCreateListItemResponseMock()); + }); + + it('DELETE to the lists endpoint with the list item', async () => { + const abortCtrl = new AbortController(); + await deleteListItem({ + http: httpMock, + signal: abortCtrl.signal, + id: 'item_id', + refresh: 'true', + }); + + expect(httpMock.fetch).toHaveBeenCalledWith( + '/api/lists/items', + expect.objectContaining({ + method: 'DELETE', + query: { id: 'item_id', refresh: 'true' }, + }) + ); + }); + + it('returns the deleted list item', async () => { + const abortCtrl = new AbortController(); + const result = await deleteListItem({ + http: httpMock, + signal: abortCtrl.signal, + id: 'item_id', + }); + + expect(result).toEqual(getDeletedListItemResponseMock()); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/index.ts new file mode 100644 index 0000000000000..1605b68ee04cd --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/index.ts @@ -0,0 +1,225 @@ +/* + * 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 { + FindListItemSchema, + ListItemSchema, + deleteListItemSchema, + patchListItemSchema, + createListItemSchema, + findListItemSchema, + foundListItemSchema, + listItemSchema, + FoundListItemSchema, + DeleteListItemSchema, + PatchListItemSchema, + CreateListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { chain, fromEither, 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 { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { + ApiParams, + FindListItemsParams, + DeleteListItemParams, + PatchListItemParams, + CreateListItemParams, +} from '../types'; +import { toError, toPromise } from '../fp_utils'; + +const version = '2023-10-31'; + +/** + * Fetch list items + */ +const findListItems = async ({ + http, + cursor, + page, + // eslint-disable-next-line @typescript-eslint/naming-convention + list_id, + // eslint-disable-next-line @typescript-eslint/naming-convention + per_page, + signal, + // eslint-disable-next-line @typescript-eslint/naming-convention + sort_field, + // eslint-disable-next-line @typescript-eslint/naming-convention + sort_order, + filter, +}: ApiParams & FindListItemSchema): Promise => { + return http.fetch(`${LIST_ITEM_URL}/_find`, { + method: 'GET', + query: { + cursor, + page, + per_page, + sort_field, + sort_order, + list_id, + filter, + }, + signal, + version, + }); +}; + +const findListItemsWithValidation = async ({ + cursor, + http, + pageIndex, + pageSize, + signal, + sortField, + sortOrder, + filter, + listId, +}: FindListItemsParams): Promise => + pipe( + { + cursor: cursor != null ? cursor.toString() : undefined, + page: pageIndex != null ? pageIndex.toString() : undefined, + per_page: pageSize != null ? pageSize.toString() : undefined, + sort_field: sortField != null ? sortField.toString() : undefined, + filter: filter != null ? filter.toString() : undefined, + sort_order: sortOrder, + list_id: listId, + }, + (payload) => fromEither(validateEither(findListItemSchema, payload)), + chain((payload) => tryCatch(() => findListItems({ http, signal, ...payload }), toError)), + chain((response) => fromEither(validateEither(foundListItemSchema, response))), + flow(toPromise) + ); + +export { findListItemsWithValidation as findListItems }; + +const deleteListItem = async ({ + http, + id, + signal, + refresh, +}: ApiParams & DeleteListItemSchema): Promise => + http.fetch(LIST_ITEM_URL, { + method: 'DELETE', + query: { id, refresh }, + signal, + version, + }); + +const deleteListItemWithValidation = async ({ + http, + id, + signal, + refresh, +}: DeleteListItemParams): Promise => + pipe( + { id, refresh }, + (payload) => fromEither(validateEither(deleteListItemSchema, payload)), + chain((payload) => + tryCatch( + () => + deleteListItem({ + http, + signal, + ...payload, + value: undefined, + list_id: undefined, + }), + toError + ) + ), + chain((response) => fromEither(validateEither(listItemSchema, response))), + flow(toPromise) + ); + +export { deleteListItemWithValidation as deleteListItem }; + +const patchListItem = async ({ + http, + id, + signal, + value, + _version, +}: ApiParams & PatchListItemSchema): Promise => + http.fetch(LIST_ITEM_URL, { + method: 'PATCH', + body: JSON.stringify({ id, value, _version }), + signal, + version, + }); + +const patchListItemWithValidation = async ({ + http, + id, + signal, + value, + refresh, + _version, +}: PatchListItemParams): Promise => + pipe( + { id, value, _version, refresh }, + (payload) => fromEither(validateEither(patchListItemSchema, payload)), + chain((payload) => + tryCatch( + () => + patchListItem({ + http, + signal, + ...payload, + }), + toError + ) + ), + chain((response) => fromEither(validateEither(listItemSchema, response))), + flow(toPromise) + ); + +export { patchListItemWithValidation as patchListItem }; + +const createListItem = async ({ + http, + signal, + value, + // eslint-disable-next-line @typescript-eslint/naming-convention + list_id, + refresh, +}: ApiParams & CreateListItemSchema): Promise => + http.fetch(LIST_ITEM_URL, { + method: 'POST', + body: JSON.stringify({ value, list_id, refresh }), + signal, + version, + }); + +const createListItemWithValidation = async ({ + http, + signal, + value, + refresh, + listId, +}: CreateListItemParams): Promise => + pipe( + { list_id: listId, value, refresh }, + (payload) => fromEither(validateEither(createListItemSchema, payload)), + chain((payload) => + tryCatch( + () => + createListItem({ + http, + signal, + ...payload, + }), + toError + ) + ), + chain((response) => fromEither(validateEither(listItemSchema, response))), + flow(toPromise) + ); + +export { createListItemWithValidation as createListItem }; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/index.ts new file mode 100644 index 0000000000000..2dddd844c5f23 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/index.ts @@ -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 type { FoundListItemSchema, ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { getListItemResponseMock } from './list_item_schema.mock'; + +export const getFoundListSchemaMock = (): FoundListItemSchema => ({ + cursor: '123', + data: [getListItemResponseMock()], + page: 1, + per_page: 1, + total: 1, +}); + +export const getCreateListItemResponseMock = (): ListItemSchema => getListItemResponseMock(); +export const getUpdatedListItemResponseMock = (): ListItemSchema => getListItemResponseMock(); +export const getDeletedListItemResponseMock = (): ListItemSchema => getListItemResponseMock(); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/list_item_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/list_item_schema.mock.ts new file mode 100644 index 0000000000000..726f49e9d0d3f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/list_item_api/mocks/response/list_item_schema.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +export const getListItemResponseMock = (): ListItemSchema => ({ + _version: '1', + '@timestamp': '2020-08-11T11:22:13.670Z', + created_at: '2020-08-11T11:22:13.670Z', + created_by: 'elastic', + deserializer: 'some deserializer', + id: 'bpdB3XMBx7pemMHopQ6M', + list_id: 'list_id', + meta: {}, + serializer: 'some serializer', + tie_breaker_id: '17d3befb-dc22-4b3c-a286-b5504c4fbeeb', + type: 'keyword', + updated_at: '2020-08-11T11:22:13.670Z', + updated_by: 'elastic', + value: 'some keyword', +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/types.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/types.ts new file mode 100644 index 0000000000000..54aa89936d73c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/src/types.ts @@ -0,0 +1,85 @@ +/* + * 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 type { + SortFieldOrUndefined, + SortOrderOrUndefined, + Type, + Refresh, + RefreshWithWaitFor, +} 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 { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + fetch: (...args: any) => any; +} + +export interface ApiParams { + http: HttpStart; + signal: AbortSignal; +} +export type ApiPayload = Omit; + +export interface FindListsParams extends ApiParams { + cursor?: string | undefined; + pageSize: number | undefined; + pageIndex: number | undefined; + sortOrder?: SortOrderOrUndefined; + sortField?: SortFieldOrUndefined; +} + +export interface FindListItemsParams extends ApiParams { + cursor?: string | undefined; + pageSize: number | undefined; + pageIndex: number | undefined; + sortOrder?: SortOrderOrUndefined; + sortField?: SortFieldOrUndefined; + filter: string | undefined; + listId: string; +} + +export interface ImportListParams extends ApiParams { + file: File; + listId: string | undefined; + type: Type | undefined; + refresh?: RefreshWithWaitFor; +} + +export interface DeleteListParams extends ApiParams { + deleteReferences?: boolean; + id: string; + ignoreReferences?: boolean; +} + +export interface DeleteListItemParams extends ApiParams { + refresh?: Refresh; + id: string; +} + +export interface PatchListItemParams extends ApiParams { + refresh?: Refresh; + id: string; + value: string; + _version?: string; +} + +export interface CreateListItemParams extends ApiParams { + refresh?: RefreshWithWaitFor; + value: string; + listId: string; +} + +export interface ExportListParams extends ApiParams { + listId: string; +} + +export interface GetListByIdParams extends ApiParams { + id: string; +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-api/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/tsconfig.json new file mode 100644 index 0000000000000..10dbca8030001 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-api/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "kbn_references": [ + "@kbn/securitysolution-io-ts-list-types", + "@kbn/securitysolution-io-ts-utils", + "@kbn/securitysolution-list-constants", + "@kbn/core-http-browser", + "@kbn/core-http-browser-mocks", + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-list-constants/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/README.md similarity index 100% rename from packages/kbn-securitysolution-list-constants/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-list-constants/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/index.ts new file mode 100644 index 0000000000000..746294c8908fe --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/index.ts @@ -0,0 +1,146 @@ +/* + * 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 { deepFreeze } from '@kbn/std'; + +/** + * Value list routes + */ +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`; + +/** + * Internal value list routes + */ +export const INTERNAL_LIST_URL = '/internal/lists'; +export const INTERNAL_FIND_LISTS_BY_SIZE = `${INTERNAL_LIST_URL}/_find_lists_by_size` as const; +export const INTERNAL_EXCEPTION_FILTER = `${INTERNAL_LIST_URL}/_create_filter` as const; + +/** + * Exception list routes + */ +export const EXCEPTION_LIST_URL = '/api/exception_lists'; +export const EXCEPTION_LIST_ITEM_URL = '/api/exception_lists/items'; + +/** + * Internal exception list routes + */ +export const INTERNAL_EXCEPTION_LIST_URL = `/internal${EXCEPTION_LIST_URL}`; +export const INTERNAL_EXCEPTIONS_LIST_ENSURE_CREATED_URL = `${INTERNAL_EXCEPTION_LIST_URL}/_create`; + +/** + * 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'; + +/** + * This ID is used for _both_ the Saved Object ID and for the list_id + * for the single global space agnostic endpoint list + */ +export const ENDPOINT_LIST_ID = 'endpoint_list'; + +/** The name of the single global space agnostic endpoint list */ +export const ENDPOINT_LIST_NAME = 'Endpoint Security Exception List'; + +/** The description of the single global space agnostic endpoint list */ +export const ENDPOINT_LIST_DESCRIPTION = 'Endpoint Security Exception List'; + +export const MAX_EXCEPTION_LIST_SIZE = 10000; + +export const MAXIMUM_SMALL_VALUE_LIST_SIZE = 65536; + +export const MAXIMUM_SMALL_IP_RANGE_VALUE_LIST_DASH_SIZE = 200; + +/** + * List definitions for Endpoint Artifact + */ +export const ENDPOINT_ARTIFACT_LISTS = deepFreeze({ + trustedApps: { + id: 'endpoint_trusted_apps', + name: 'Endpoint Security Trusted Apps List', + description: 'Endpoint Security Trusted Apps List', + }, + eventFilters: { + id: 'endpoint_event_filters', + name: 'Endpoint Security Event Filters List', + description: 'Endpoint Security Event Filters List', + }, + hostIsolationExceptions: { + id: 'endpoint_host_isolation_exceptions', + name: 'Endpoint Security Host isolation exceptions List', + description: 'Endpoint Security Host isolation exceptions List', + }, + blocklists: { + id: 'endpoint_blocklists', + name: 'Endpoint Security Blocklists List', + description: 'Endpoint Security Blocklists List', + }, +}); + +/** + * The IDs of all Endpoint artifact lists + */ +export const ENDPOINT_ARTIFACT_LIST_IDS = Object.freeze( + Object.values(ENDPOINT_ARTIFACT_LISTS).map(({ id }) => id) +); + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_TRUSTED_APPS_LIST_ID = ENDPOINT_ARTIFACT_LISTS.trustedApps.id; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_TRUSTED_APPS_LIST_NAME = ENDPOINT_ARTIFACT_LISTS.trustedApps.name; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION = + ENDPOINT_ARTIFACT_LISTS.trustedApps.description; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_EVENT_FILTERS_LIST_ID = ENDPOINT_ARTIFACT_LISTS.eventFilters.id; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_EVENT_FILTERS_LIST_NAME = ENDPOINT_ARTIFACT_LISTS.eventFilters.name; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION = + ENDPOINT_ARTIFACT_LISTS.eventFilters.description; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID = + ENDPOINT_ARTIFACT_LISTS.hostIsolationExceptions.id; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_NAME = + ENDPOINT_ARTIFACT_LISTS.hostIsolationExceptions.name; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_DESCRIPTION = + ENDPOINT_ARTIFACT_LISTS.hostIsolationExceptions.description; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_BLOCKLISTS_LIST_ID = ENDPOINT_ARTIFACT_LISTS.blocklists.id; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_BLOCKLISTS_LIST_NAME = ENDPOINT_ARTIFACT_LISTS.blocklists.name; + +/** @deprecated Use `ENDPOINT_ARTIFACT_LISTS` instead */ +export const ENDPOINT_BLOCKLISTS_LIST_DESCRIPTION = ENDPOINT_ARTIFACT_LISTS.blocklists.description; diff --git a/packages/kbn-securitysolution-list-constants/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-list-constants/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-list-constants/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/package.json new file mode 100644 index 0000000000000..f57bdd68a2cc5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/securitysolution-list-constants", + "version": "1.0.0", + "description": "security solution list constants to use across plugins such lists, security_solution, cases, etc...", + "license": "Elastic License 2.0", + "private": true +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/tsconfig.json new file mode 100644 index 0000000000000..0d3f96d6a17b5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-constants/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "kbn_references": [ + "@kbn/std" + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-list-hooks/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/README.md similarity index 100% rename from packages/kbn-securitysolution-list-hooks/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/index.ts new file mode 100644 index 0000000000000..8e5fdecab1863 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/index.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +export * from './src/transforms'; +export * from './src/use_api'; +export * from './src/use_create_list_index'; +export * from './src/use_cursor'; +export * from './src/use_delete_list'; +export * from './src/use_exception_lists'; +export * from './src/use_export_list'; +export * from './src/use_find_lists'; +export * from './src/use_find_lists_by_size'; +export * from './src/use_import_list'; +export * from './src/use_persist_exception_item'; +export * from './src/use_persist_exception_list'; +export * from './src/use_read_list_index'; +export * from './src/use_read_list_privileges'; +export * from './src/use_find_list_items'; +export * from './src/use_create_list_item'; +export * from './src/use_delete_list_item'; +export * from './src/use_patch_list_item'; +export * from './src/use_get_list_by_id'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/jest.config.js b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/jest.config.js new file mode 100644 index 0000000000000..7b0430c9bf092 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks'], +}; diff --git a/packages/kbn-securitysolution-list-hooks/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-list-hooks/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/package.json new file mode 100644 index 0000000000000..8a2ead4291bd3 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/securitysolution-list-hooks", + "version": "1.0.0", + "description": "Security solution list ReactJS hooks", + "license": "Elastic License 2.0", + "private": true, + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/constants.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/constants.ts new file mode 100644 index 0000000000000..377c980531a4e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/constants.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export const READ_INDEX_QUERY_KEY = ['detectionEngine', 'listIndex']; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/index.ts new file mode 100644 index 0000000000000..dd0e180eba269 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './transforms'; +export * from './use_api'; +export * from './use_create_list_index'; +export * from './use_cursor'; +export * from './use_delete_list'; +export * from './use_exception_lists'; +export * from './use_export_list'; +export * from './use_find_lists'; +export * from './use_import_list'; +export * from './use_persist_exception_item'; +export * from './use_persist_exception_list'; +export * from './use_read_list_index'; +export * from './use_read_list_privileges'; +export * from './use_find_list_items'; +export * from './use_create_list_item'; +export * from './use_delete_list_item'; +export * from './use_patch_list_item'; +export * from './use_get_list_by_id'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/constants.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/constants.mock.ts new file mode 100644 index 0000000000000..762d1eb243cf7 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/constants.mock.ts @@ -0,0 +1,99 @@ +/* + * 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 { + CommentsArray, + EntriesArray, + Entry, + EntryMatch, + EntryNested, + OsTypeArray, +} from '@kbn/securitysolution-io-ts-list-types'; + +export const DATE_NOW = '2020-04-20T15:25:31.830Z'; +export const USER = 'some user'; +export const ELASTIC_USER = 'elastic'; +export const NAME = 'some name'; +export const DESCRIPTION = 'some description'; +export const LIST_ID = 'some-list-id'; +export const TIE_BREAKER = '6a76b69d-80df-4ab2-8c3e-85f466b06a0e'; + +export const META = {}; +export const TYPE = 'ip'; + +export const VERSION = 1; +export const IMMUTABLE = false; +// Exception List specific +export const ID = 'uuid_here'; +export const NAMESPACE_TYPE = 'single'; +export const OS_TYPES: OsTypeArray = ['windows']; +export const TAGS = []; +export const UPDATED_COMMENTS = [ + { + comment: 'old comment', + id: 'old_created_id', + }, + { + comment: 'new comment', + id: 'new_id', + }, +]; +export const COMMENTS = []; +export const ENTRIES: EntriesArray = [ + { + entries: [{ field: 'nested.field', operator: 'included', type: 'match', value: 'some value' }], + field: 'some.parentField', + type: 'nested', + }, + { field: 'some.not.nested.field', operator: 'included', type: 'match', value: 'some value' }, +]; +export const ITEM_ID = 'some-list-item-id'; +export const ITEM_TYPE = 'simple'; +export const LIST_ITEM_ID = 'some-list-item-id'; +// ENTRIES_WITH_IDS should only be used to mock out functionality of a collection of transforms +// that are UI specific and useful for UI concerns that are inserted between the +// API and the actual user interface. In some ways these might be viewed as +// technical debt or to compensate for the differences and preferences +// of how ReactJS might prefer data vs. how we want to model data. +export const ENTRIES_WITH_IDS: EntriesArray = [ + { + entries: [ + { + field: 'nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as EntryMatch & { id: string }, + ], + field: 'some.parentField', + id: '123', + type: 'nested', + } as EntryNested & { id: string }, + { + field: 'some.not.nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as Entry & { id: string }, +]; + +export const COMMENTS_WITH_CREATEDAT_CREATEDBY: CommentsArray = [ + { + comment: 'old comment', + id: 'old_created_id', + created_at: '2022-01-08T15:25:31.830Z', + created_by: 'elastic', + }, + { + comment: 'new comment', + id: 'new_id', + created_at: '2022-05-14T15:25:31.830Z', + created_by: 'elastic', + }, +]; diff --git a/packages/kbn-securitysolution-list-hooks/src/mocks/request/create_exception_list_item_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/request/create_exception_list_item_schema.mock.ts similarity index 76% rename from packages/kbn-securitysolution-list-hooks/src/mocks/request/create_exception_list_item_schema.mock.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/request/create_exception_list_item_schema.mock.ts index 5727a271a9bf8..ff9789a7995b9 100644 --- a/packages/kbn-securitysolution-list-hooks/src/mocks/request/create_exception_list_item_schema.mock.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/request/create_exception_list_item_schema.mock.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 type { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/request/update_exception_list_item_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/request/update_exception_list_item_schema.mock.ts new file mode 100644 index 0000000000000..47b0030c316aa --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/request/update_exception_list_item_schema.mock.ts @@ -0,0 +1,51 @@ +/* + * 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 type { UpdateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { + DESCRIPTION, + ENTRIES, + ID, + ITEM_ID, + ITEM_TYPE, + LIST_ITEM_ID, + META, + NAME, + NAMESPACE_TYPE, + OS_TYPES, + TAGS, + UPDATED_COMMENTS, +} from '../constants.mock'; + +export const getUpdateExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({ + _version: undefined, + comments: UPDATED_COMMENTS, + description: DESCRIPTION, + entries: ENTRIES, + id: ID, + item_id: LIST_ITEM_ID, + meta: META, + name: NAME, + namespace_type: NAMESPACE_TYPE, + os_types: ['linux'], + tags: TAGS, + type: ITEM_TYPE, +}); + +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + * after doing a get of the structure. + */ +export const getUpdateMinimalExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({ + description: DESCRIPTION, + entries: ENTRIES, + item_id: ITEM_ID, + name: NAME, + os_types: OS_TYPES, + type: ITEM_TYPE, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/response/exception_list_item_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/response/exception_list_item_schema.mock.ts new file mode 100644 index 0000000000000..acb7204da9b76 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/response/exception_list_item_schema.mock.ts @@ -0,0 +1,70 @@ +/* + * 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 type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { + COMMENTS, + DATE_NOW, + DESCRIPTION, + ELASTIC_USER, + ENTRIES, + ITEM_ID, + ITEM_TYPE, + LIST_ID, + META, + NAME, + NAMESPACE_TYPE, + OS_TYPES, + TIE_BREAKER, + USER, +} from '../constants.mock'; + +export const getExceptionListItemSchemaMock = ( + overrides?: Partial +): ExceptionListItemSchema => ({ + _version: undefined, + comments: COMMENTS, + created_at: DATE_NOW, + created_by: USER, + description: DESCRIPTION, + entries: ENTRIES, + expire_time: undefined, + id: '1', + item_id: 'endpoint_list_item', + list_id: 'endpoint_list_id', + meta: META, + name: NAME, + namespace_type: NAMESPACE_TYPE, + os_types: [], + tags: ['user added string for a tag', 'malware'], + tie_breaker_id: TIE_BREAKER, + type: ITEM_TYPE, + updated_at: DATE_NOW, + updated_by: USER, + ...(overrides || {}), +}); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getExceptionListItemResponseMockWithoutAutoGeneratedValues = + (): Partial => ({ + comments: [], + created_by: ELASTIC_USER, + description: DESCRIPTION, + entries: ENTRIES, + item_id: ITEM_ID, + list_id: LIST_ID, + name: NAME, + namespace_type: 'single', + os_types: OS_TYPES, + tags: [], + type: ITEM_TYPE, + updated_by: ELASTIC_USER, + }); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/response/found_list_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/response/found_list_schema.mock.ts new file mode 100644 index 0000000000000..1691221842d39 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/response/found_list_schema.mock.ts @@ -0,0 +1,18 @@ +/* + * 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 type { FoundListSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { getListResponseMock } from './list_schema.mock'; + +export const getFoundListSchemaMock = (): FoundListSchema => ({ + cursor: '123', + data: [getListResponseMock()], + page: 1, + per_page: 1, + total: 1, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/response/list_schema.mock.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/response/list_schema.mock.ts new file mode 100644 index 0000000000000..b2b66ad4636c2 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/mocks/response/list_schema.mock.ts @@ -0,0 +1,55 @@ +/* + * 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 type { ListSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { + DATE_NOW, + DESCRIPTION, + ELASTIC_USER, + IMMUTABLE, + LIST_ID, + META, + NAME, + TIE_BREAKER, + TYPE, + USER, + VERSION, +} from '../constants.mock'; + +export const getListResponseMock = (): ListSchema => ({ + '@timestamp': DATE_NOW, + _version: undefined, + created_at: DATE_NOW, + created_by: USER, + description: DESCRIPTION, + deserializer: undefined, + id: LIST_ID, + immutable: IMMUTABLE, + meta: META, + name: NAME, + serializer: undefined, + tie_breaker_id: TIE_BREAKER, + type: TYPE, + updated_at: DATE_NOW, + updated_by: USER, + version: VERSION, +}); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getListResponseMockWithoutAutoGeneratedValues = (): Partial => ({ + created_by: ELASTIC_USER, + description: DESCRIPTION, + immutable: IMMUTABLE, + name: NAME, + type: TYPE, + updated_by: ELASTIC_USER, + version: VERSION, +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/transforms/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/transforms/index.test.ts new file mode 100644 index 0000000000000..dc94fcddd8498 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/transforms/index.test.ts @@ -0,0 +1,297 @@ +/* + * 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 type { + CreateExceptionListItemSchema, + Entry, + EntryMatch, + EntryNested, + ExceptionListItemSchema, + UpdateExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { + addIdToExceptionItemEntries, + removeIdFromExceptionItemsEntries, + transformInput, + transformOutput, +} from '../..'; + +import { getCreateExceptionListItemSchemaMock } from '../mocks/request/create_exception_list_item_schema.mock'; +import { getUpdateExceptionListItemSchemaMock } from '../mocks/request/update_exception_list_item_schema.mock'; +import { getExceptionListItemSchemaMock } from '../mocks/response/exception_list_item_schema.mock'; +import { COMMENTS_WITH_CREATEDAT_CREATEDBY, ENTRIES_WITH_IDS } from '../mocks/constants.mock'; + +jest.mock('uuid', () => ({ + v4: jest.fn().mockReturnValue('123'), +})); + +describe('Exceptions transforms', () => { + describe('transformOutput', () => { + it('should return same output as input with stripped ids per entry - CreateExceptionListItemSchema', () => { + const mockCreateExceptionItem = { + ...getCreateExceptionListItemSchemaMock(), + entries: ENTRIES_WITH_IDS, + }; + const output = transformOutput(mockCreateExceptionItem); + const expectedOutput: CreateExceptionListItemSchema = getCreateExceptionListItemSchemaMock(); + + expect(output).toEqual(expectedOutput); + }); + + it('should return same output as input with stripped ids per entry - UpdateExceptionListItemSchema', () => { + const mockUpdateExceptionItem = { + ...getUpdateExceptionListItemSchemaMock(), + entries: ENTRIES_WITH_IDS, + }; + const output = transformOutput(mockUpdateExceptionItem); + const expectedOutput: UpdateExceptionListItemSchema = getUpdateExceptionListItemSchemaMock(); + + expect(output).toEqual(expectedOutput); + }); + it('should return output as input with stripped createdAt and createdBy per entry - UpdateExceptionListItemSchema', () => { + const mockUpdateExceptionItem = { + ...getUpdateExceptionListItemSchemaMock(), + entries: ENTRIES_WITH_IDS, + comments: COMMENTS_WITH_CREATEDAT_CREATEDBY, + }; + const output = transformOutput(mockUpdateExceptionItem); + const expectedOutput: UpdateExceptionListItemSchema = getUpdateExceptionListItemSchemaMock(); + + expect(output).toEqual(expectedOutput); + }); + }); + + describe('transformInput', () => { + it('should return same output as input with added ids per entry', () => { + const mockExceptionItem = getExceptionListItemSchemaMock(); + const output = transformInput(mockExceptionItem); + const expectedOutput: ExceptionListItemSchema = { + ...getExceptionListItemSchemaMock(), + entries: ENTRIES_WITH_IDS, + }; + + expect(output).toEqual(expectedOutput); + }); + }); + + describe('addIdToExceptionItemEntries', () => { + it('should return same output as input with added ids per entry', () => { + const mockExceptionItem: ExceptionListItemSchema = { + ...getExceptionListItemSchemaMock(), + entries: [ + { + field: 'some.not.nested.field', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + }; + const output = addIdToExceptionItemEntries(mockExceptionItem); + const expectedOutput: ExceptionListItemSchema = { + ...getExceptionListItemSchemaMock(), + entries: [ + { + field: 'some.not.nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as Entry & { id: string }, + ], + }; + + expect(output).toEqual(expectedOutput); + }); + + it('should return same output as input with added ids per nested entry', () => { + const mockExceptionItem: ExceptionListItemSchema = { + ...getExceptionListItemSchemaMock(), + entries: [ + { + entries: [ + { + field: 'nested.field', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + field: 'some.parentField', + type: 'nested', + }, + ], + }; + const output = addIdToExceptionItemEntries(mockExceptionItem); + const expectedOutput: ExceptionListItemSchema = { + ...getExceptionListItemSchemaMock(), + entries: [ + { + entries: [ + { + field: 'nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as EntryMatch & { id: string }, + ], + field: 'some.parentField', + id: '123', + type: 'nested', + } as EntryNested & { id: string }, + ], + }; + + expect(output).toEqual(expectedOutput); + }); + }); + + describe('removeIdFromExceptionItemsEntries', () => { + it('should return same output as input with stripped ids per entry - CreateExceptionListItemSchema', () => { + const mockCreateExceptionItem = { + ...getCreateExceptionListItemSchemaMock(), + entries: [ + { + field: 'some.not.nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as Entry & { id: string }, + ], + }; + const output = removeIdFromExceptionItemsEntries(mockCreateExceptionItem); + const expectedOutput: CreateExceptionListItemSchema = { + ...getCreateExceptionListItemSchemaMock(), + entries: [ + { + field: 'some.not.nested.field', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + }; + + expect(output).toEqual(expectedOutput); + }); + + it('should return same output as input with stripped ids per nested entry - CreateExceptionListItemSchema', () => { + const mockCreateExceptionItem = { + ...getCreateExceptionListItemSchemaMock(), + entries: [ + { + entries: [ + { + field: 'nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as EntryMatch & { id: string }, + ], + field: 'some.parentField', + id: '123', + type: 'nested', + } as EntryNested & { id: string }, + ], + }; + const output = removeIdFromExceptionItemsEntries(mockCreateExceptionItem); + const expectedOutput: CreateExceptionListItemSchema = { + ...getCreateExceptionListItemSchemaMock(), + entries: [ + { + entries: [ + { + field: 'nested.field', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + field: 'some.parentField', + type: 'nested', + }, + ], + }; + + expect(output).toEqual(expectedOutput); + }); + + it('should return same output as input with stripped ids per entry - UpdateExceptionListItemSchema', () => { + const mockUpdateExceptionItem = { + ...getUpdateExceptionListItemSchemaMock(), + entries: [ + { + field: 'some.not.nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as Entry & { id: string }, + ], + }; + const output = removeIdFromExceptionItemsEntries(mockUpdateExceptionItem); + const expectedOutput: UpdateExceptionListItemSchema = { + ...getUpdateExceptionListItemSchemaMock(), + entries: [ + { + field: 'some.not.nested.field', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + }; + + expect(output).toEqual(expectedOutput); + }); + + it('should return same output as input with stripped ids per nested entry - UpdateExceptionListItemSchema', () => { + const mockUpdateExceptionItem = { + ...getUpdateExceptionListItemSchemaMock(), + entries: [ + { + entries: [ + { + field: 'nested.field', + id: '123', + operator: 'included', + type: 'match', + value: 'some value', + } as EntryMatch & { id: string }, + ], + field: 'some.parentField', + id: '123', + type: 'nested', + } as EntryNested & { id: string }, + ], + }; + const output = removeIdFromExceptionItemsEntries(mockUpdateExceptionItem); + const expectedOutput: UpdateExceptionListItemSchema = { + ...getUpdateExceptionListItemSchemaMock(), + entries: [ + { + entries: [ + { + field: 'nested.field', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + field: 'some.parentField', + type: 'nested', + }, + ], + }; + + expect(output).toEqual(expectedOutput); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/transforms/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/transforms/index.ts new file mode 100644 index 0000000000000..276c52b000af9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/transforms/index.ts @@ -0,0 +1,136 @@ +/* + * 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 { flow } from 'fp-ts/lib/function'; +import { addIdToItem, removeIdFromItem } from '@kbn/securitysolution-utils'; +import type { + CreateExceptionListItemSchema, + EntriesArray, + Entry, + ExceptionListItemSchema, + UpdateExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; + +// These are a collection of transforms that are UI specific and useful for UI concerns +// that are inserted between the API and the actual user interface. In some ways these +// might be viewed as technical debt or to compensate for the differences and preferences +// of how ReactJS might prefer data vs. how we want to model data. Each function should have +// a description giving context around the transform. + +/** + * Transforms the output of exception items to compensate for technical debt or UI concerns such as + * ReactJS preferences for having ids within arrays if the data is not modeled that way. + * + * If you add a new transform of the output called "myNewTransform" do it + * in the form of: + * flow(removeIdFromExceptionItemsEntries, myNewTransform)(exceptionItem) + * + * @param exceptionItem The exceptionItem to transform the output of + * @returns The exceptionItem transformed from the output + */ +export const transformOutput = ( + exceptionItem: UpdateExceptionListItemSchema | ExceptionListItemSchema +): UpdateExceptionListItemSchema | ExceptionListItemSchema => + flow( + removeCreatedAtCreatedByFromCommentsOnUpdate, + removeIdFromExceptionItemsEntries + )(exceptionItem); + +export const transformNewItemOutput = ( + exceptionItem: CreateExceptionListItemSchema +): CreateExceptionListItemSchema => flow(removeIdFromExceptionItemsEntries)(exceptionItem); + +/** + * Transforms the output of rules to compensate for technical debt or UI concerns such as + * ReactJS preferences for having ids within arrays if the data is not modeled that way. + * + * If you add a new transform of the input called "myNewTransform" do it + * in the form of: + * flow(addIdToExceptionItemEntries, myNewTransform)(exceptionItem) + * + * @param exceptionItem The exceptionItem to transform the output of + * @returns The exceptionItem transformed from the output + */ +export const transformInput = (exceptionItem: ExceptionListItemSchema): ExceptionListItemSchema => + flow(addIdToExceptionItemEntries)(exceptionItem); + +/** + * This adds an id to the incoming exception item entries as ReactJS prefers to have + * an id added to them for use as a stable id. Later if we decide to change the data + * model to have id's within the array then this code should be removed. If not, then + * this code should stay as an adapter for ReactJS. + * + * This does break the type system slightly as we are lying a bit to the type system as we return + * the same exceptionItem as we have previously but are augmenting the arrays with an id which TypeScript + * doesn't mind us doing here. However, downstream you will notice that you have an id when the type + * does not indicate it. In that case use (ExceptionItem & { id: string }) temporarily if you're using the id. If you're not, + * you can ignore the id and just use the normal TypeScript with ReactJS. + * + * @param exceptionItem The exceptionItem to add an id to the threat matches. + * @returns exceptionItem The exceptionItem but with id added to the exception item entries + */ +export const addIdToExceptionItemEntries = ( + exceptionItem: ExceptionListItemSchema +): ExceptionListItemSchema => { + const entries = exceptionItem.entries.map((entry) => { + if (entry.type === 'nested') { + return addIdToItem({ + ...entry, + entries: entry.entries.map((nestedEntry) => addIdToItem(nestedEntry)), + }); + } else { + return addIdToItem(entry); + } + }); + return { ...exceptionItem, entries }; +}; + +/** + * This removes an id from the exceptionItem entries as ReactJS prefers to have + * an id added to them for use as a stable id. Later if we decide to change the data + * model to have id's within the array then this code should be removed. If not, then + * this code should stay as an adapter for ReactJS. + * + * @param exceptionItem The exceptionItem to remove an id from the entries. + * @returns exceptionItem The exceptionItem but with id removed from the entries + */ +export const removeIdFromExceptionItemsEntries = ( + exceptionItem: T +): T => { + const { entries } = exceptionItem; + const entriesNoId = entries.map((entry) => { + if (entry.type === 'nested') { + return removeIdFromItem({ + ...entry, + entries: entry.entries.map((nestedEntry) => removeIdFromItem(nestedEntry)), + }); + } else { + return removeIdFromItem(entry); + } + }); + return { ...exceptionItem, entries: entriesNoId }; +}; + +/** + * This removes createdAt, createdBy from the exceptionItem if a comment was added to + * the Exception item, and return the comment message with id to prevent creating the commet + * twice + * @param exceptionItem The exceptionItem to remove createdAt, createdBy from the comments array. + * @returns exceptionItem The exceptionItem with comments do not have createdAt, createdBy. + */ +export const removeCreatedAtCreatedByFromCommentsOnUpdate = ( + exceptionItem: UpdateExceptionListItemSchema | ExceptionListItemSchema +) => { + const { comments } = exceptionItem; + if (!comments || !comments.length) return exceptionItem; + + const entriesNoCreatedAtAndBy = comments.map(({ comment, id }) => ({ + comment, + id, + })); + return { ...exceptionItem, comments: entriesNoCreatedAtAndBy }; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts new file mode 100644 index 0000000000000..673eaff90b1af --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts @@ -0,0 +1,315 @@ +/* + * 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 { useMemo } from 'react'; +import type { + CreateExceptionListItemSchema, + ExceptionListItemSchema, + ExceptionListSchema, + UpdateExceptionListItemSchema, + ApiCallFindListsItemsMemoProps, + ApiCallMemoProps, + ApiListExportProps, + ApiCallGetExceptionFilterFromIdsMemoProps, + ApiCallGetExceptionFilterFromExceptionsMemoProps, + ApiListDuplicateProps, +} from '@kbn/securitysolution-io-ts-list-types'; +import * as Api from '@kbn/securitysolution-list-api'; +import { getIdsAndNamespaces } from '@kbn/securitysolution-list-utils'; +import type { HttpStart } from '@kbn/core-http-browser'; + +import { transformInput, transformNewItemOutput, transformOutput } from '../transforms'; + +export interface ExceptionsApi { + addExceptionListItem: (arg: { + listItem: CreateExceptionListItemSchema; + }) => Promise; + updateExceptionListItem: (arg: { + listItem: UpdateExceptionListItemSchema; + }) => Promise; + deleteExceptionItem: (arg: ApiCallMemoProps) => Promise; + deleteExceptionList: (arg: ApiCallMemoProps) => Promise; + duplicateExceptionList: (arg: ApiListDuplicateProps) => Promise; + getExceptionItem: ( + arg: ApiCallMemoProps & { onSuccess: (arg: ExceptionListItemSchema) => void } + ) => Promise; + getExceptionList: ( + arg: ApiCallMemoProps & { onSuccess: (arg: ExceptionListSchema) => void } + ) => Promise; + getExceptionListsItems: (arg: ApiCallFindListsItemsMemoProps) => Promise; + getExceptionFilterFromIds: (arg: ApiCallGetExceptionFilterFromIdsMemoProps) => Promise; + getExceptionFilterFromExceptions: ( + arg: ApiCallGetExceptionFilterFromExceptionsMemoProps + ) => Promise; + exportExceptionList: (arg: ApiListExportProps) => Promise; +} + +export const useApi = (http: HttpStart): ExceptionsApi => { + return useMemo( + (): ExceptionsApi => ({ + async addExceptionListItem({ + listItem, + }: { + listItem: CreateExceptionListItemSchema; + }): Promise { + const abortCtrl = new AbortController(); + const sanitizedItem: CreateExceptionListItemSchema = transformNewItemOutput(listItem); + + return Api.addExceptionListItem({ + http, + listItem: sanitizedItem, + signal: abortCtrl.signal, + }); + }, + async deleteExceptionItem({ + id, + namespaceType, + onSuccess, + onError, + }: ApiCallMemoProps): Promise { + const abortCtrl = new AbortController(); + + try { + await Api.deleteExceptionListItemById({ + http, + id, + namespaceType, + signal: abortCtrl.signal, + }); + onSuccess(); + } catch (error) { + onError(error); + } + }, + async deleteExceptionList({ + id, + namespaceType, + onSuccess, + onError, + }: ApiCallMemoProps): Promise { + const abortCtrl = new AbortController(); + + try { + await Api.deleteExceptionListById({ + http, + id, + namespaceType, + signal: abortCtrl.signal, + }); + onSuccess(); + } catch (error) { + onError(error); + } + }, + async duplicateExceptionList({ + includeExpiredExceptions, + listId, + namespaceType, + onError, + onSuccess, + }: ApiListDuplicateProps): Promise { + const abortCtrl = new AbortController(); + + try { + const newList = await Api.duplicateExceptionList({ + http, + includeExpiredExceptions, + listId, + namespaceType, + signal: abortCtrl.signal, + }); + onSuccess(newList); + } catch (error) { + onError(error); + } + }, + async exportExceptionList({ + id, + includeExpiredExceptions, + listId, + namespaceType, + onError, + onSuccess, + }: ApiListExportProps): Promise { + const abortCtrl = new AbortController(); + + try { + const blob = await Api.exportExceptionList({ + http, + id, + includeExpiredExceptions, + listId, + namespaceType, + signal: abortCtrl.signal, + }); + onSuccess(blob); + } catch (error) { + onError(error); + } + }, + async getExceptionItem({ + id, + namespaceType, + onSuccess, + onError, + }: ApiCallMemoProps & { onSuccess: (arg: ExceptionListItemSchema) => void }): Promise { + const abortCtrl = new AbortController(); + + try { + const item = transformInput( + await Api.fetchExceptionListItemById({ + http, + id, + namespaceType, + signal: abortCtrl.signal, + }) + ); + onSuccess(item); + } catch (error) { + onError(error); + } + }, + async getExceptionList({ + id, + namespaceType, + onSuccess, + onError, + }: ApiCallMemoProps & { onSuccess: (arg: ExceptionListSchema) => void }): Promise { + const abortCtrl = new AbortController(); + + try { + const list = await Api.fetchExceptionListById({ + http, + id, + namespaceType, + signal: abortCtrl.signal, + }); + onSuccess(list); + } catch (error) { + onError(error); + } + }, + async getExceptionListsItems({ + lists, + filter, + pagination, + showDetectionsListsOnly, + showEndpointListsOnly, + onSuccess, + onError, + }: ApiCallFindListsItemsMemoProps): Promise { + const abortCtrl = new AbortController(); + const { ids, namespaces } = getIdsAndNamespaces({ + lists, + showDetection: showDetectionsListsOnly, + showEndpoint: showEndpointListsOnly, + }); + + try { + if (ids.length > 0 && namespaces.length > 0) { + const { + data, + page, + per_page: perPage, + total, + } = await Api.fetchExceptionListsItemsByListIds({ + filter, + http, + listIds: ids, + namespaceTypes: namespaces, + pagination, + signal: abortCtrl.signal, + }); + onSuccess({ + // This data transform is UI specific and useful for UI concerns + // to compensate for the differences and preferences of how ReactJS might prefer + // data vs. how we want to model data. View `transformInput` for more details + exceptions: data.map((item) => transformInput(item)), + pagination: { + page, + perPage, + total, + }, + }); + } else { + onSuccess({ + exceptions: [], + pagination: { + page: 0, + perPage: pagination.perPage != null ? pagination.perPage : 0, + total: 0, + }, + }); + } + } catch (error) { + onError(error); + } + }, + async getExceptionFilterFromIds({ + exceptionListIds, + chunkSize, + alias, + excludeExceptions, + onSuccess, + onError, + }: ApiCallGetExceptionFilterFromIdsMemoProps): Promise { + const abortCtrl = new AbortController(); + try { + const { filter } = await Api.getExceptionFilterFromExceptionListIds({ + http, + exceptionListIds, + signal: abortCtrl.signal, + chunkSize, + alias, + excludeExceptions, + }); + onSuccess(filter); + } catch (error) { + onError(error); + } + }, + async getExceptionFilterFromExceptions({ + exceptions, + chunkSize, + alias, + excludeExceptions, + onSuccess, + onError, + }: ApiCallGetExceptionFilterFromExceptionsMemoProps): Promise { + const abortCtrl = new AbortController(); + try { + const { filter } = await Api.getExceptionFilterFromExceptions({ + http, + exceptions, + signal: abortCtrl.signal, + chunkSize, + alias, + excludeExceptions, + }); + onSuccess(filter); + } catch (error) { + onError(error); + } + }, + async updateExceptionListItem({ + listItem, + }: { + listItem: UpdateExceptionListItemSchema; + }): Promise { + const abortCtrl = new AbortController(); + const sanitizedItem: UpdateExceptionListItemSchema = transformOutput(listItem); + + return Api.updateExceptionListItem({ + http, + listItem: sanitizedItem, + signal: abortCtrl.signal, + }); + }, + }), + [http] + ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_create_list_index/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_create_list_index/index.ts new file mode 100644 index 0000000000000..9cfaf30a9e2a4 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_create_list_index/index.ts @@ -0,0 +1,41 @@ +/* + * 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 { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { createListIndex, ApiParams } from '@kbn/securitysolution-list-api'; +import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +import { READ_INDEX_QUERY_KEY } from '../constants'; + +const createListIndexWithOptionalSignal = withOptionalSignal(createListIndex); + +export const useCreateListIndex = ({ + http, + onError, +}: { + http: ApiParams['http']; + onError?: (err: unknown) => void; +}) => { + const queryClient = useQueryClient(); + + const { mutate, isLoading, error } = useMutation( + () => createListIndexWithOptionalSignal({ http }), + { + onSuccess: () => { + queryClient.invalidateQueries(READ_INDEX_QUERY_KEY); + }, + onError, + } + ); + + return { + start: mutate, + loading: isLoading, + error, + }; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_create_list_item/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_create_list_item/index.ts new file mode 100644 index 0000000000000..eaafc36d87334 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_create_list_item/index.ts @@ -0,0 +1,41 @@ +/* + * 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 type { UseMutationOptions } from '@tanstack/react-query'; +import type { ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import type { IHttpFetchError } from '@kbn/core-http-browser'; +import { useMutation } from '@tanstack/react-query'; +import { createListItem } from '@kbn/securitysolution-list-api'; +import type { CreateListItemParams } from '@kbn/securitysolution-list-api'; +import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +import { useInvalidateListItemQuery } from '../use_find_list_items'; + +const createListItemWithOptionalSignal = withOptionalSignal(createListItem); + +export const CREATE_LIST_ITEM_MUTATION_KEY = ['POST', 'LIST_ITEM_CREATE']; +type CreateListMutationParams = Omit; + +export const useCreateListItemMutation = ( + options?: UseMutationOptions, CreateListMutationParams> +) => { + const invalidateListItemQuery = useInvalidateListItemQuery(); + return useMutation, CreateListMutationParams>( + ({ listId, value, http }) => + createListItemWithOptionalSignal({ listId, value, http, refresh: 'wait_for' }), + { + ...options, + mutationKey: CREATE_LIST_ITEM_MUTATION_KEY, + onSettled: (...args) => { + invalidateListItemQuery(); + if (options?.onSettled) { + options.onSettled(...args); + } + }, + } + ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.test.ts new file mode 100644 index 0000000000000..714c310f6d5ea --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.test.ts @@ -0,0 +1,119 @@ +/* + * 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 { renderHook, act } from '@testing-library/react'; + +import { UseCursorProps, useCursor } from '.'; + +describe('useCursor', () => { + it('returns undefined cursor if no values have been set', () => { + const { result } = renderHook((props: UseCursorProps) => useCursor(props), { + initialProps: { pageIndex: 0, pageSize: 0 }, + }); + + expect(result.current[0]).toBeUndefined(); + }); + + it('retrieves a cursor for the next page of a given page size', () => { + const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { + initialProps: { pageIndex: 0, pageSize: 0 }, + }); + rerender({ pageIndex: 1, pageSize: 1 }); + act(() => { + result.current[1]('new_cursor'); + }); + + expect(result.current[0]).toBeUndefined(); + + rerender({ pageIndex: 2, pageSize: 1 }); + expect(result.current[0]).toEqual('new_cursor'); + }); + + it('returns undefined cursor for an unknown search', () => { + const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { + initialProps: { pageIndex: 0, pageSize: 0 }, + }); + act(() => { + result.current[1]('new_cursor'); + }); + + rerender({ pageIndex: 1, pageSize: 2 }); + expect(result.current[0]).toBeUndefined(); + }); + + it('remembers cursor through rerenders', () => { + const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { + initialProps: { pageIndex: 0, pageSize: 0 }, + }); + + rerender({ pageIndex: 1, pageSize: 1 }); + act(() => { + result.current[1]('new_cursor'); + }); + + rerender({ pageIndex: 2, pageSize: 1 }); + expect(result.current[0]).toEqual('new_cursor'); + + rerender({ pageIndex: 0, pageSize: 0 }); + expect(result.current[0]).toBeUndefined(); + + rerender({ pageIndex: 2, pageSize: 1 }); + expect(result.current[0]).toEqual('new_cursor'); + }); + + it('remembers multiple cursors', () => { + const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { + initialProps: { pageIndex: 0, pageSize: 0 }, + }); + + rerender({ pageIndex: 1, pageSize: 1 }); + act(() => { + result.current[1]('new_cursor'); + }); + rerender({ pageIndex: 2, pageSize: 2 }); + act(() => { + result.current[1]('another_cursor'); + }); + + rerender({ pageIndex: 2, pageSize: 1 }); + expect(result.current[0]).toEqual('new_cursor'); + + rerender({ pageIndex: 3, pageSize: 2 }); + expect(result.current[0]).toEqual('another_cursor'); + }); + + it('returns the "nearest" cursor for the given page size', () => { + const { rerender, result } = renderHook((props: UseCursorProps) => useCursor(props), { + initialProps: { pageIndex: 0, pageSize: 0 }, + }); + + rerender({ pageIndex: 1, pageSize: 2 }); + act(() => { + result.current[1]('cursor1'); + }); + rerender({ pageIndex: 2, pageSize: 2 }); + act(() => { + result.current[1]('cursor2'); + }); + rerender({ pageIndex: 3, pageSize: 2 }); + act(() => { + result.current[1]('cursor3'); + }); + + rerender({ pageIndex: 2, pageSize: 2 }); + expect(result.current[0]).toEqual('cursor1'); + + rerender({ pageIndex: 3, pageSize: 2 }); + expect(result.current[0]).toEqual('cursor2'); + + rerender({ pageIndex: 4, pageSize: 2 }); + expect(result.current[0]).toEqual('cursor3'); + + rerender({ pageIndex: 6, pageSize: 2 }); + expect(result.current[0]).toEqual('cursor3'); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.ts new file mode 100644 index 0000000000000..1bc85c63363c8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_cursor/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback, useState } from 'react'; + +export interface UseCursorProps { + pageIndex: number; + pageSize: number; +} +type Cursor = string | undefined; +type SetCursor = (cursor: Cursor) => void; +type UseCursor = (props: UseCursorProps) => [Cursor, SetCursor]; + +const hash = (props: UseCursorProps): string => JSON.stringify(props); + +export const useCursor: UseCursor = ({ pageIndex, pageSize }) => { + const [cache, setCache] = useState>({}); + + const setCursor = useCallback( + (cursor) => { + setCache({ + ...cache, + [hash({ pageIndex: pageIndex + 1, pageSize })]: cursor, + }); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [pageIndex, pageSize] + ); + + let cursor: Cursor; + for (let i = pageIndex; i >= 0; i--) { + const currentProps = { pageIndex: i, pageSize }; + cursor = cache[hash(currentProps)]; + if (cursor) { + break; + } + } + + return [cursor, setCursor]; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_delete_list/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_delete_list/index.ts new file mode 100644 index 0000000000000..ae427947ab66c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_delete_list/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { deleteList } from '@kbn/securitysolution-list-api'; +import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +const deleteListWithOptionalSignal = withOptionalSignal(deleteList); + +export const useDeleteList = () => useAsync(deleteListWithOptionalSignal); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_delete_list_item/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_delete_list_item/index.ts new file mode 100644 index 0000000000000..04c608f9c841f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_delete_list_item/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { UseMutationOptions } from '@tanstack/react-query'; +import type { ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { useMutation } from '@tanstack/react-query'; +import { deleteListItem } from '@kbn/securitysolution-list-api'; +import type { IHttpFetchError } from '@kbn/core-http-browser'; +import type { DeleteListItemParams } from '@kbn/securitysolution-list-api'; +import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; +import { useInvalidateListItemQuery } from '../use_find_list_items'; + +const deleteListItemWithOptionalSignal = withOptionalSignal(deleteListItem); + +export const DELETE_LIST_ITEM_MUTATION_KEY = ['POST', ' DELETE_LIST_ITEM_MUTATION']; +type DeleteListMutationParams = Omit; + +export const useDeleteListItemMutation = ( + options?: UseMutationOptions, DeleteListMutationParams> +) => { + const invalidateListItemQuery = useInvalidateListItemQuery(); + return useMutation, DeleteListMutationParams>( + ({ id, http }) => deleteListItemWithOptionalSignal({ id, http }), + { + ...options, + mutationKey: DELETE_LIST_ITEM_MUTATION_KEY, + onSettled: (...args) => { + invalidateListItemQuery(); + if (options?.onSettled) { + options.onSettled(...args); + } + }, + } + ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts new file mode 100644 index 0000000000000..8a8e2aadf258c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts @@ -0,0 +1,140 @@ +/* + * 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 { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import type { + ExceptionListSchema, + UseExceptionListsProps, + Pagination, + Sort, +} from '@kbn/securitysolution-io-ts-list-types'; +import { fetchExceptionLists } from '@kbn/securitysolution-list-api'; + +import { getFilters } from '@kbn/securitysolution-list-utils'; + +export type Func = () => void; +export type ReturnExceptionLists = [ + loading: boolean, + exceptionLists: ExceptionListSchema[], + pagination: Pagination, + setPagination: React.Dispatch>, + fetchLists: Func | null, + sort: Sort, + setSort: React.Dispatch> +]; + +const DEFAULT_PAGINATION = { + page: 1, + perPage: 20, + total: 0, +}; + +const DEFAULT_SORT = { + field: 'created_at', + order: 'desc', +}; + +/** + * Hook for fetching ExceptionLists + * + * @param http Kibana http service + * @param errorMessage message shown to user if error occurs + * @param filterOptions filter by certain fields + * @param namespaceTypes spaces to be searched + * @param notifications kibana service for displaying toasters + * @param hideLists a list of listIds we don't want to query + * @param initialPagination + * + */ +export const useExceptionLists = ({ + errorMessage, + http, + initialPagination = DEFAULT_PAGINATION, + filterOptions = {}, + namespaceTypes, + notifications, + hideLists = [], + initialSort = DEFAULT_SORT, +}: UseExceptionListsProps): ReturnExceptionLists => { + const [exceptionLists, setExceptionLists] = useState([]); + const [pagination, setPagination] = useState(initialPagination); + const [sort, setSort] = useState(initialSort); + const [loading, setLoading] = useState(true); + const abortCtrlRef = useRef(); + + const namespaceTypesAsString = useMemo(() => namespaceTypes.join(','), [namespaceTypes]); + const filters = useMemo( + (): string => + getFilters({ + filters: filterOptions, + namespaceTypes, + hideLists, + }), + [namespaceTypes, filterOptions, hideLists] + ); + + const fetchData = useCallback(async (): Promise => { + try { + setLoading(true); + + abortCtrlRef.current = new AbortController(); + + const { + page, + per_page: perPage, + total, + data, + } = await fetchExceptionLists({ + filters, + http, + namespaceTypes: namespaceTypesAsString, + pagination: { + page: pagination.page, + perPage: pagination.perPage, + }, + sort, + signal: abortCtrlRef.current.signal, + }); + + setPagination({ + page, + perPage, + total, + }); + setExceptionLists(data); + setLoading(false); + } catch (error) { + if (error.name !== 'AbortError') { + notifications.toasts.addError(error, { + title: errorMessage, + }); + setExceptionLists([]); + setPagination(DEFAULT_PAGINATION); + setLoading(false); + } + } + }, [ + errorMessage, + filters, + http, + namespaceTypesAsString, + notifications.toasts, + pagination.page, + pagination.perPage, + sort, + ]); + + useEffect(() => { + fetchData(); + + return (): void => { + abortCtrlRef.current?.abort(); + }; + }, [fetchData]); + + return [loading, exceptionLists, pagination, setPagination, fetchData, sort, setSort]; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_export_list/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_export_list/index.ts new file mode 100644 index 0000000000000..bdaec5e503615 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_export_list/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { exportList } from '@kbn/securitysolution-list-api'; +import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +const exportListWithOptionalSignal = withOptionalSignal(exportList); + +export const useExportList = () => useAsync(exportListWithOptionalSignal); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_list_items/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_list_items/index.ts new file mode 100644 index 0000000000000..86ed9892fa95e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_list_items/index.ts @@ -0,0 +1,73 @@ +/* + * 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 { useCallback } from 'react'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { findListItems, ApiParams } from '@kbn/securitysolution-list-api'; +import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; +import { useCursor } from '../use_cursor'; + +const findListItemsWithOptionalSignal = withOptionalSignal(findListItems); + +const FIND_LIST_ITEMS_QUERY_KEY = 'FIND_LIST_ITEMS'; + +export const useInvalidateListItemQuery = () => { + const queryClient = useQueryClient(); + + return useCallback(() => { + queryClient.invalidateQueries([FIND_LIST_ITEMS_QUERY_KEY], { + refetchType: 'active', + }); + }, [queryClient]); +}; + +export const useFindListItems = ({ + pageIndex, + pageSize, + sortField, + sortOrder, + listId, + filter, + http, +}: { + pageIndex: number; + pageSize: number; + sortField: string; + sortOrder: 'asc' | 'desc'; + listId: string; + filter: string; + http: ApiParams['http']; +}) => { + const [cursor, setCursor] = useCursor({ pageIndex, pageSize }); + return useQuery( + [FIND_LIST_ITEMS_QUERY_KEY, pageIndex, pageSize, sortField, sortOrder, listId, filter], + async ({ signal }) => { + const response = await findListItemsWithOptionalSignal({ + http, + signal, + pageIndex, + pageSize, + sortField, + sortOrder, + listId, + cursor, + filter, + }); + return response; + }, + { + keepPreviousData: true, + refetchOnWindowFocus: false, + retry: false, + onSuccess: (data) => { + if (data?.cursor) { + setCursor(data?.cursor); + } + }, + } + ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.test.ts new file mode 100644 index 0000000000000..0c60b3ebebb3e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.test.ts @@ -0,0 +1,37 @@ +/* + * 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 { waitFor, renderHook, act } from '@testing-library/react'; + +import { useFindLists } from '.'; +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; +import * as Api from '@kbn/securitysolution-list-api'; + +import { getFoundListSchemaMock } from '../mocks/response/found_list_schema.mock'; + +jest.mock('@kbn/securitysolution-list-api'); + +describe('useFindLists', () => { + let httpMock: ReturnType; + + beforeEach(() => { + httpMock = httpServiceMock.createStartContract(); + (Api.findLists as jest.Mock).mockResolvedValue(getFoundListSchemaMock()); + }); + + it('invokes Api.findLists', async () => { + const { result } = renderHook(() => useFindLists()); + act(() => { + result.current.start({ http: httpMock, pageIndex: 1, pageSize: 10 }); + }); + await waitFor(() => + expect(Api.findLists).toHaveBeenCalledWith( + expect.objectContaining({ http: httpMock, pageIndex: 1, pageSize: 10 }) + ) + ); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.ts new file mode 100644 index 0000000000000..0ad30728be4a8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_lists/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { findLists } from '@kbn/securitysolution-list-api'; +import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +const findListsWithOptionalSignal = withOptionalSignal(findLists); + +export const useFindLists = () => useAsync(findListsWithOptionalSignal); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_lists_by_size/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_lists_by_size/index.ts new file mode 100644 index 0000000000000..e1132bdaab293 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_find_lists_by_size/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { findListsBySize } from '@kbn/securitysolution-list-api'; +import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +const findListsBySizeWithOptionalSignal = withOptionalSignal(findListsBySize); + +export const useFindListsBySize = () => useAsync(findListsBySizeWithOptionalSignal); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_get_list_by_id/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_get_list_by_id/index.ts new file mode 100644 index 0000000000000..394b48352a32b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_get_list_by_id/index.ts @@ -0,0 +1,26 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; +import { getListById, ApiParams } from '@kbn/securitysolution-list-api'; +import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +const getListByIdWithOptionalSignal = withOptionalSignal(getListById); + +const GET_LIST_BY_ID_QUERY_KEY = 'GET_LIST_BY_ID'; +export const useGetListById = ({ http, id }: { http: ApiParams['http']; id: string }) => { + return useQuery( + [GET_LIST_BY_ID_QUERY_KEY, id], + async ({ signal }) => { + const respone = await getListByIdWithOptionalSignal({ http, signal, id }); + return respone; + }, + { + refetchOnWindowFocus: false, + } + ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_import_list/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_import_list/index.ts new file mode 100644 index 0000000000000..4499b7220128e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_import_list/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { importList } from '@kbn/securitysolution-list-api'; +import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +const importListWithOptionalSignal = withOptionalSignal(importList); + +export const useImportList = () => useAsync(importListWithOptionalSignal); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_patch_list_item/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_patch_list_item/index.ts new file mode 100644 index 0000000000000..e321006a0b687 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_patch_list_item/index.ts @@ -0,0 +1,40 @@ +/* + * 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 type { UseMutationOptions } from '@tanstack/react-query'; +import type { ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { useMutation } from '@tanstack/react-query'; +import type { PatchListItemParams } from '@kbn/securitysolution-list-api'; +import { patchListItem } from '@kbn/securitysolution-list-api'; +import type { IHttpFetchError } from '@kbn/core-http-browser'; +import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; +import { useInvalidateListItemQuery } from '../use_find_list_items'; + +const patchListItemWithOptionalSignal = withOptionalSignal(patchListItem); + +export const PATCH_LIST_ITEM_MUTATION_KEY = ['PATCH', 'LIST_ITEM_MUTATION']; +type PatchListMutationParams = Omit; + +export const usePatchListItemMutation = ( + options?: UseMutationOptions, PatchListMutationParams> +) => { + const invalidateListItemQuery = useInvalidateListItemQuery(); + return useMutation, PatchListMutationParams>( + ({ id, value, _version, http }: PatchListMutationParams) => + patchListItemWithOptionalSignal({ id, value, http, refresh: 'true', _version }), + { + ...options, + mutationKey: PATCH_LIST_ITEM_MUTATION_KEY, + onSettled: (...args) => { + invalidateListItemQuery(); + if (options?.onSettled) { + options.onSettled(...args); + } + }, + } + ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_item/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_item/index.ts new file mode 100644 index 0000000000000..ad239016ed054 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_item/index.ts @@ -0,0 +1,109 @@ +/* + * 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 { Dispatch, useEffect, useRef, useState } from 'react'; +import type { + CreateExceptionListItemSchema, + PersistHookProps, + UpdateExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { addExceptionListItem, updateExceptionListItem } from '@kbn/securitysolution-list-api'; + +import { transformNewItemOutput, transformOutput } from '../transforms'; + +interface PersistReturnExceptionItem { + isLoading: boolean; + isSaved: boolean; +} + +export type ReturnPersistExceptionItem = [ + PersistReturnExceptionItem, + Dispatch +]; + +// TODO: Add this to @kbn/securitysolution-list-hooks + +/** + * Hook for creating or updating ExceptionListItem + * + * @param http Kibana http service + * @param onError error callback + * + */ +export const usePersistExceptionItem = ({ + http, + onError, +}: PersistHookProps): ReturnPersistExceptionItem => { + const [exceptionListItem, setExceptionItem] = useState< + CreateExceptionListItemSchema | UpdateExceptionListItemSchema | null + >(null); + const [isSaved, setIsSaved] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const isUpdateExceptionItem = (item: unknown): item is UpdateExceptionListItemSchema => + Boolean(item && (item as UpdateExceptionListItemSchema).id != null); + const isSubscribed = useRef(false); + + useEffect(() => { + let abortCtrl: AbortController | null = null; + isSubscribed.current = true; + setIsSaved(false); + + const saveExceptionItem = async (): Promise => { + if (exceptionListItem === null) { + return; + } + + try { + abortCtrl = new AbortController(); + setIsLoading(true); + + if (isUpdateExceptionItem(exceptionListItem)) { + // Please see `x-pack/solutions/security/plugins/lists/public/exceptions/transforms.ts` doc notes + // for context around the temporary `id` + const transformedList = transformOutput(exceptionListItem); + + await updateExceptionListItem({ + http, + listItem: transformedList, + signal: abortCtrl.signal, + }); + } else { + // Please see `x-pack/solutions/security/plugins/lists/public/exceptions/transforms.ts` doc notes + // for context around the temporary `id` + const transformedList = transformNewItemOutput(exceptionListItem); + + await addExceptionListItem({ + http, + listItem: transformedList, + signal: abortCtrl.signal, + }); + } + + if (isSubscribed.current) { + setIsSaved(true); + } + } catch (error) { + if (isSubscribed.current) { + onError(error); + } + } finally { + if (isSubscribed.current) { + setIsLoading(false); + } + } + }; + + saveExceptionItem(); + + return (): void => { + isSubscribed.current = false; + abortCtrl?.abort(); + }; + }, [http, exceptionListItem, onError]); + + return [{ isLoading, isSaved }, setExceptionItem]; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_list/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_list/index.ts new file mode 100644 index 0000000000000..6814a19679c57 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_list/index.ts @@ -0,0 +1,79 @@ +/* + * 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 { Dispatch, useEffect, useState } from 'react'; +import type { + AddExceptionList, + PersistHookProps, + UpdateExceptionListSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { addExceptionList, updateExceptionList } from '@kbn/securitysolution-list-api'; + +interface PersistReturnExceptionList { + isLoading: boolean; + isSaved: boolean; +} + +export type ReturnPersistExceptionList = [ + PersistReturnExceptionList, + Dispatch +]; + +/** + * Hook for creating or updating ExceptionList + * + * @param http Kibana http service + * @param onError error callback + * + */ +export const usePersistExceptionList = ({ + http, + onError, +}: PersistHookProps): ReturnPersistExceptionList => { + const [exceptionList, setExceptionList] = useState(null); + const [isSaved, setIsSaved] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const isUpdateExceptionList = (item: unknown): item is UpdateExceptionListSchema => + Boolean(item && (item as UpdateExceptionListSchema).id != null); + + useEffect(() => { + let isSubscribed = true; + const abortCtrl = new AbortController(); + setIsSaved(false); + + const saveExceptionList = async (): Promise => { + if (exceptionList != null) { + try { + setIsLoading(true); + if (isUpdateExceptionList(exceptionList)) { + await updateExceptionList({ http, list: exceptionList, signal: abortCtrl.signal }); + } else { + await addExceptionList({ http, list: exceptionList, signal: abortCtrl.signal }); + } + if (isSubscribed) { + setIsSaved(true); + } + } catch (error) { + if (isSubscribed) { + onError(error); + } + } + if (isSubscribed) { + setIsLoading(false); + } + } + }; + + saveExceptionList(); + return (): void => { + isSubscribed = false; + abortCtrl.abort(); + }; + }, [http, exceptionList, onError]); + + return [{ isLoading, isSaved }, setExceptionList]; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_read_list_index/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_read_list_index/index.ts new file mode 100644 index 0000000000000..2bb2a7018857d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_read_list_index/index.ts @@ -0,0 +1,49 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; + +import { readListIndex, ApiParams } from '@kbn/securitysolution-list-api'; +import { withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +import { READ_INDEX_QUERY_KEY } from '../constants'; + +const readListIndexWithOptionalSignal = withOptionalSignal(readListIndex); + +export const useReadListIndex = ({ + http, + isEnabled, + onError, +}: { + isEnabled: boolean; + http: ApiParams['http']; + onError?: (err: unknown) => void; +}) => { + const query = useQuery( + READ_INDEX_QUERY_KEY, + async ({ signal }) => { + if (!isEnabled) { + return null; + } + + return readListIndexWithOptionalSignal({ http, signal }); + }, + { + onError, + retry: false, + refetchOnWindowFocus: false, + enabled: isEnabled, + staleTime: Infinity, + } + ); + + return { + result: query.data, + loading: query.isFetching, + error: query.error, + }; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_read_list_privileges/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_read_list_privileges/index.ts new file mode 100644 index 0000000000000..1e96118228b5d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_read_list_privileges/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { readListPrivileges } from '@kbn/securitysolution-list-api'; +import { useAsync, withOptionalSignal } from '@kbn/securitysolution-hook-utils'; + +const readListPrivilegesWithOptionalSignal = withOptionalSignal(readListPrivileges); + +export const useReadListPrivileges = () => useAsync(readListPrivilegesWithOptionalSignal); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/tsconfig.json new file mode 100644 index 0000000000000..f2583861bced6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "kbn_references": [ + "@kbn/securitysolution-hook-utils", + "@kbn/securitysolution-io-ts-list-types", + "@kbn/securitysolution-list-api", + "@kbn/securitysolution-list-utils", + "@kbn/securitysolution-utils", + "@kbn/core-http-browser-mocks", + "@kbn/core-http-browser", + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-list-utils/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/README.md similarity index 100% rename from packages/kbn-securitysolution-list-utils/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-list-utils/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/index.ts new file mode 100644 index 0000000000000..cd6928dd89e34 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export * from './src/autocomplete_operators'; +export * from './src/get_exception_list_type'; +export * from './src/get_filters'; +export * from './src/get_general_filters'; +export * from './src/get_ids_and_namespaces'; +export * from './src/get_saved_object_type'; +export * from './src/get_saved_object_types'; +export * from './src/has_large_value_list'; +export * from './src/helpers'; +export * from './src/types'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/jest.config.js b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/jest.config.js new file mode 100644 index 0000000000000..e3fc2abb342ab --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/solutions/security/packages/kbn-securitysolution-list-utils'], +}; diff --git a/packages/kbn-securitysolution-list-utils/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-list-utils/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-list-utils/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/package.json new file mode 100644 index 0000000000000..585acd8e3d70c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/securitysolution-list-utils", + "version": "1.0.0", + "description": "security solution list utilities", + "license": "Elastic License 2.0", + "private": true, + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts new file mode 100644 index 0000000000000..430a0dbc3a1d8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts @@ -0,0 +1,158 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { + ListOperatorEnum as OperatorEnum, + ListOperatorTypeEnum as OperatorTypeEnum, +} from '@kbn/securitysolution-io-ts-list-types'; +import { OperatorOption } from '../types'; + +export const isOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.isOperatorLabel', { + defaultMessage: 'is', + }), + operator: OperatorEnum.INCLUDED, + type: OperatorTypeEnum.MATCH, + value: 'is', +}; + +export const isNotOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.isNotOperatorLabel', { + defaultMessage: 'is not', + }), + operator: OperatorEnum.EXCLUDED, + type: OperatorTypeEnum.MATCH, + value: 'is_not', +}; + +export const isOneOfOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.isOneOfOperatorLabel', { + defaultMessage: 'is one of', + }), + operator: OperatorEnum.INCLUDED, + type: OperatorTypeEnum.MATCH_ANY, + value: 'is_one_of', +}; + +export const isNotOneOfOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.isNotOneOfOperatorLabel', { + defaultMessage: 'is not one of', + }), + operator: OperatorEnum.EXCLUDED, + type: OperatorTypeEnum.MATCH_ANY, + value: 'is_not_one_of', +}; + +export const existsOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.existsOperatorLabel', { + defaultMessage: 'exists', + }), + operator: OperatorEnum.INCLUDED, + type: OperatorTypeEnum.EXISTS, + value: 'exists', +}; + +export const doesNotExistOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.doesNotExistOperatorLabel', { + defaultMessage: 'does not exist', + }), + operator: OperatorEnum.EXCLUDED, + type: OperatorTypeEnum.EXISTS, + value: 'does_not_exist', +}; + +export const isInListOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.isInListOperatorLabel', { + defaultMessage: 'is in list', + }), + operator: OperatorEnum.INCLUDED, + type: OperatorTypeEnum.LIST, + value: 'is_in_list', +}; + +export const isNotInListOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.isNotInListOperatorLabel', { + defaultMessage: 'is not in list', + }), + operator: OperatorEnum.EXCLUDED, + type: OperatorTypeEnum.LIST, + value: 'is_not_in_list', +}; + +export const matchesOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.matchesOperatorLabel', { + defaultMessage: 'matches', + }), + operator: OperatorEnum.INCLUDED, + type: OperatorTypeEnum.WILDCARD, + value: 'matches', +}; + +export const doesNotMatchOperator: OperatorOption = { + message: i18n.translate('lists.exceptions.doesNotMatchOperatorLabel', { + defaultMessage: 'does not match', + }), + operator: OperatorEnum.EXCLUDED, + type: OperatorTypeEnum.WILDCARD, + value: 'does_not_match', +}; + +export const EVENT_FILTERS_OPERATORS: OperatorOption[] = [ + isOperator, + isNotOperator, + isOneOfOperator, + isNotOneOfOperator, + matchesOperator, + doesNotMatchOperator, +]; + +/* + * !IMPORTANT! - Please only add to this list if it is an operator + * supported by the detection engine. + */ +export const DETECTION_ENGINE_EXCEPTION_OPERATORS: OperatorOption[] = [ + isOperator, + isNotOperator, + isOneOfOperator, + isNotOneOfOperator, + existsOperator, + doesNotExistOperator, + isInListOperator, + isNotInListOperator, + matchesOperator, + doesNotMatchOperator, +]; + +export const ALL_OPERATORS: OperatorOption[] = [ + isOperator, + isNotOperator, + isOneOfOperator, + isNotOneOfOperator, + existsOperator, + doesNotExistOperator, + isInListOperator, + isNotInListOperator, + matchesOperator, + doesNotMatchOperator, +]; + +export const EXCEPTION_OPERATORS_SANS_LISTS: OperatorOption[] = [ + isOperator, + isNotOperator, + isOneOfOperator, + isNotOneOfOperator, + existsOperator, + doesNotExistOperator, + matchesOperator, + doesNotMatchOperator, +]; + +export const EXCEPTION_OPERATORS_ONLY_LISTS: OperatorOption[] = [ + isInListOperator, + isNotInListOperator, +]; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts new file mode 100644 index 0000000000000..29dba94f76761 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts @@ -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 type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; + +import { exceptionListAgnosticSavedObjectType } from '../types'; + +export const getExceptionListType = ({ + savedObjectType, +}: { + savedObjectType: string; +}): NamespaceType => { + if (savedObjectType === exceptionListAgnosticSavedObjectType) { + return 'agnostic'; + } else { + return 'single'; + } +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts new file mode 100644 index 0000000000000..a88a78479cf54 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts @@ -0,0 +1,207 @@ +/* + * 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 { getFilters } from '.'; + +describe('getFilters', () => { + describe('single', () => { + test('it properly formats when no filters and hide lists contains few list ids', () => { + const filter = getFilters({ + filters: {}, + namespaceTypes: ['single'], + hideLists: ['listId-1', 'listId-2', 'listId-3'], + }); + + expect(filter).toEqual( + '(not exception-list.attributes.list_id: listId-1*) AND (not exception-list.attributes.list_id: listId-2*) AND (not exception-list.attributes.list_id: listId-3*)' + ); + }); + test('it properly formats when no filters and hide lists contains one list id', () => { + const filter = getFilters({ + filters: {}, + namespaceTypes: ['single'], + hideLists: ['listId-1'], + }); + + expect(filter).toEqual('(not exception-list.attributes.list_id: listId-1*)'); + }); + test('it properly formats when no filters and no hide lists', () => { + const filter = getFilters({ + filters: {}, + namespaceTypes: ['single'], + hideLists: [], + }); + + expect(filter).toEqual(''); + }); + test('it properly formats when filters passed and hide lists contains few list ids', () => { + const filter = getFilters({ + filters: { created_by: 'moi', name: 'Sample' }, + namespaceTypes: ['single'], + hideLists: ['listId-1', 'listId-2', 'listId-3'], + }); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: listId-1*) AND (not exception-list.attributes.list_id: listId-2*) AND (not exception-list.attributes.list_id: listId-3*)' + ); + }); + test('it properly formats when filters passed and hide lists contains one list id', () => { + const filter = getFilters({ + filters: { created_by: 'moi', name: 'Sample' }, + namespaceTypes: ['single'], + hideLists: ['listId-1'], + }); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: listId-1*)' + ); + }); + test('it properly formats when filters passed and no hide lists', () => { + const filter = getFilters({ + filters: { created_by: 'moi', name: 'Sample' }, + namespaceTypes: ['single'], + hideLists: [], + }); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample)' + ); + }); + }); + + describe('agnostic', () => { + test('it properly formats when no filters and hide lists contains few list ids', () => { + const filter = getFilters({ + filters: {}, + namespaceTypes: ['agnostic'], + hideLists: ['listId-1', 'listId-2', 'listId-3'], + }); + + expect(filter).toEqual( + '(not exception-list-agnostic.attributes.list_id: listId-1*) AND (not exception-list-agnostic.attributes.list_id: listId-2*) AND (not exception-list-agnostic.attributes.list_id: listId-3*)' + ); + }); + test('it properly formats when no filters and hide lists contains one list id', () => { + const filter = getFilters({ + filters: {}, + namespaceTypes: ['agnostic'], + hideLists: ['listId-1'], + }); + + expect(filter).toEqual('(not exception-list-agnostic.attributes.list_id: listId-1*)'); + }); + test('it properly formats when no filters and no hide lists', () => { + const filter = getFilters({ + filters: {}, + namespaceTypes: ['agnostic'], + hideLists: [], + }); + + expect(filter).toEqual(''); + }); + test('it properly formats when filters passed and hide lists contains few list ids', () => { + const filter = getFilters({ + filters: { created_by: 'moi', name: 'Sample' }, + namespaceTypes: ['agnostic'], + hideLists: ['listId-1', 'listId-2', 'listId-3'], + }); + + expect(filter).toEqual( + '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list-agnostic.attributes.list_id: listId-1*) AND (not exception-list-agnostic.attributes.list_id: listId-2*) AND (not exception-list-agnostic.attributes.list_id: listId-3*)' + ); + }); + test('it properly formats when filters passed and hide lists contains one list id', () => { + const filter = getFilters({ + filters: { created_by: 'moi', name: 'Sample' }, + namespaceTypes: ['agnostic'], + hideLists: ['listId-1'], + }); + + expect(filter).toEqual( + '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list-agnostic.attributes.list_id: listId-1*)' + ); + }); + test('it properly formats when filters passed and no hide lists', () => { + const filter = getFilters({ + filters: { created_by: 'moi', name: 'Sample' }, + namespaceTypes: ['agnostic'], + hideLists: [], + }); + + expect(filter).toEqual( + '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample)' + ); + }); + }); + + describe('single, agnostic', () => { + test('it properly formats when no filters and hide lists contains few list ids', () => { + const filter = getFilters({ + filters: {}, + namespaceTypes: ['single', 'agnostic'], + hideLists: ['listId-1', 'listId-2', 'listId-3'], + }); + + expect(filter).toEqual( + '(not exception-list.attributes.list_id: listId-1* AND not exception-list-agnostic.attributes.list_id: listId-1*) AND (not exception-list.attributes.list_id: listId-2* AND not exception-list-agnostic.attributes.list_id: listId-2*) AND (not exception-list.attributes.list_id: listId-3* AND not exception-list-agnostic.attributes.list_id: listId-3*)' + ); + }); + test('it properly formats when no filters and hide lists contains one list id', () => { + const filter = getFilters({ + filters: {}, + namespaceTypes: ['single', 'agnostic'], + hideLists: ['listId-1'], + }); + + expect(filter).toEqual( + '(not exception-list.attributes.list_id: listId-1* AND not exception-list-agnostic.attributes.list_id: listId-1*)' + ); + }); + test('it properly formats when no filters and no hide lists', () => { + const filter = getFilters({ + filters: {}, + namespaceTypes: ['single', 'agnostic'], + hideLists: [], + }); + + expect(filter).toEqual(''); + }); + test('it properly formats when filters passed and hide lists contains few list ids', () => { + const filter = getFilters({ + filters: { created_by: 'moi', name: 'Sample' }, + namespaceTypes: ['single', 'agnostic'], + hideLists: ['listId-1', 'listId-2', 'listId-3'], + }); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: listId-1* AND not exception-list-agnostic.attributes.list_id: listId-1*) AND (not exception-list.attributes.list_id: listId-2* AND not exception-list-agnostic.attributes.list_id: listId-2*) AND (not exception-list.attributes.list_id: listId-3* AND not exception-list-agnostic.attributes.list_id: listId-3*)' + ); + }); + test('it properly formats when filters passed and hide lists contains one list id', () => { + const filter = getFilters({ + filters: { created_by: 'moi', name: 'Sample' }, + namespaceTypes: ['single', 'agnostic'], + hideLists: ['listId-1'], + }); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: listId-1* AND not exception-list-agnostic.attributes.list_id: listId-1*)' + ); + }); + test('it properly formats when filters passed and no hide lists', () => { + const filter = getFilters({ + filters: { created_by: 'moi', name: 'Sample' }, + namespaceTypes: ['single', 'agnostic'], + hideLists: [], + }); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample)' + ); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_filters/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_filters/index.ts new file mode 100644 index 0000000000000..2bc7960de7927 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_filters/index.ts @@ -0,0 +1,30 @@ +/* + * 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 { ExceptionListFilter, NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; +import { getGeneralFilters } from '../get_general_filters'; +import { getSavedObjectTypes } from '../get_saved_object_types'; +export interface GetFiltersParams { + filters: ExceptionListFilter; + namespaceTypes: NamespaceType[]; + hideLists: readonly string[]; +} + +export const getFilters = ({ filters, namespaceTypes, hideLists }: GetFiltersParams): string => { + const namespaces = getSavedObjectTypes({ namespaceType: namespaceTypes }); + const generalFilters = getGeneralFilters(filters, namespaces); + const hideListsFilters = hideLists.map((listId) => { + const filtersByNamespace = namespaces.map((namespace) => { + return `not ${namespace}.attributes.list_id: ${listId}*`; + }); + return `(${filtersByNamespace.join(' AND ')})`; + }); + + return [generalFilters, ...hideListsFilters] + .filter((filter) => filter.trim() !== '') + .join(' AND '); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts new file mode 100644 index 0000000000000..0262023497634 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts @@ -0,0 +1,51 @@ +/* + * 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 { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; +import { getGeneralFilters } from '.'; + +describe('getGeneralFilters', () => { + test('it returns empty string if no filters', () => { + const filters = getGeneralFilters({}, ['exception-list']); + + expect(filters).toEqual(''); + }); + + test('it properly formats filters when one namespace type passed in', () => { + const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, ['exception-list']); + + expect(filters).toEqual( + '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample)' + ); + }); + + test('it properly formats filters when two namespace types passed in', () => { + const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, [ + 'exception-list', + 'exception-list-agnostic', + ]); + + expect(filters).toEqual( + '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample)' + ); + }); + + test('it properly formats filters when two types are passed in', () => { + const filters = getGeneralFilters( + { + created_by: 'moi', + name: 'Sample', + types: [ExceptionListTypeEnum.DETECTION, ExceptionListTypeEnum.RULE_DEFAULT], + }, + ['exception-list', 'exception-list-agnostic'] + ); + + expect(filters).toEqual( + '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (exception-list.attributes.type:detection OR exception-list.attributes.type:rule_default OR exception-list-agnostic.attributes.type:detection OR exception-list-agnostic.attributes.type:rule_default)' + ); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts new file mode 100644 index 0000000000000..7960617fad485 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts @@ -0,0 +1,35 @@ +/* + * 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 { ExceptionListFilter } from '@kbn/securitysolution-io-ts-list-types'; +import { isArray } from 'lodash'; +import { get } from 'lodash/fp'; +import { SavedObjectType } from '../types'; + +export const getGeneralFilters = ( + filters: ExceptionListFilter, + namespaceTypes: SavedObjectType[] +): string => { + return Object.keys(filters) + .map((filterKey) => { + const value = get(filterKey, filters); + if (isArray(value) || (value != null && value.trim() !== '')) { + const filtersByNamespace = namespaceTypes + .map((namespace) => { + const fieldToSearch = + filterKey === 'name' ? 'name.text' : filterKey === 'types' ? 'type' : filterKey; + return isArray(value) + ? value.map((val) => `${namespace}.attributes.${fieldToSearch}:${val}`).join(' OR ') + : `${namespace}.attributes.${fieldToSearch}:${value}`; + }) + .join(' OR '); + return `(${filtersByNamespace})`; + } else return null; + }) + .filter((item) => item != null) + .join(' AND '); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts new file mode 100644 index 0000000000000..b76bc2df94ff8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts @@ -0,0 +1,104 @@ +/* + * 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 { getIdsAndNamespaces } from '.'; + +describe('getIdsAndNamespaces', () => { + test('it returns empty arrays if no lists found', async () => { + const output = getIdsAndNamespaces({ + lists: [], + showDetection: false, + showEndpoint: false, + }); + + expect(output).toEqual({ ids: [], namespaces: [] }); + }); + + test('it returns all lists if "showDetection" and "showEndpoint" are "false"', async () => { + const output = getIdsAndNamespaces({ + lists: [ + { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, + { + id: 'myListIdEndpoint', + listId: 'list_id_endpoint', + namespaceType: 'agnostic', + type: 'endpoint', + }, + ], + showDetection: false, + showEndpoint: false, + }); + + expect(output).toEqual({ + ids: ['list_id', 'list_id_endpoint'], + namespaces: ['single', 'agnostic'], + }); + }); + + test('it returns only detections lists if "showDetection" is "true"', async () => { + const output = getIdsAndNamespaces({ + lists: [ + { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, + { + id: 'myListIdEndpoint', + listId: 'list_id_endpoint', + namespaceType: 'agnostic', + type: 'endpoint', + }, + ], + showDetection: true, + showEndpoint: false, + }); + + expect(output).toEqual({ + ids: ['list_id'], + namespaces: ['single'], + }); + }); + + test('it returns only endpoint lists if "showEndpoint" is "true"', async () => { + const output = getIdsAndNamespaces({ + lists: [ + { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, + { + id: 'myListIdEndpoint', + listId: 'list_id_endpoint', + namespaceType: 'agnostic', + type: 'endpoint', + }, + ], + showDetection: false, + showEndpoint: true, + }); + + expect(output).toEqual({ + ids: ['list_id_endpoint'], + namespaces: ['agnostic'], + }); + }); + + test('it returns only detection lists if both "showEndpoint" and "showDetection" are "true"', async () => { + const output = getIdsAndNamespaces({ + lists: [ + { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, + { + id: 'myListIdEndpoint', + listId: 'list_id_endpoint', + namespaceType: 'agnostic', + type: 'endpoint', + }, + ], + showDetection: true, + showEndpoint: true, + }); + + expect(output).toEqual({ + ids: ['list_id'], + namespaces: ['single'], + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts new file mode 100644 index 0000000000000..25a7ae1931e18 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts @@ -0,0 +1,35 @@ +/* + * 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 { ExceptionListIdentifiers, NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; + +export const getIdsAndNamespaces = ({ + lists, + showDetection, + showEndpoint, +}: { + lists: ExceptionListIdentifiers[]; + showDetection: boolean; + showEndpoint: boolean; +}): { ids: string[]; namespaces: NamespaceType[] } => + lists + .filter((list) => { + if (showDetection) { + return list.type === 'detection'; + } else if (showEndpoint) { + return list.type === 'endpoint'; + } else { + return true; + } + }) + .reduce<{ ids: string[]; namespaces: NamespaceType[] }>( + (acc, { listId, namespaceType }) => ({ + ids: [...acc.ids, listId], + namespaces: [...acc.namespaces, namespaceType], + }), + { ids: [], namespaces: [] } + ); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts new file mode 100644 index 0000000000000..0ee1b134333ca --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts @@ -0,0 +1,26 @@ +/* + * 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 type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; + +import { + exceptionListAgnosticSavedObjectType, + exceptionListSavedObjectType, + SavedObjectType, +} from '../types'; + +export const getSavedObjectType = ({ + namespaceType, +}: { + namespaceType: NamespaceType; +}): SavedObjectType => { + if (namespaceType === 'agnostic') { + return exceptionListAgnosticSavedObjectType; + } else { + return exceptionListSavedObjectType; + } +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts new file mode 100644 index 0000000000000..92b6ff4a92631 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts @@ -0,0 +1,21 @@ +/* + * 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 type { NamespaceTypeArray } from '@kbn/securitysolution-io-ts-list-types'; + +import { SavedObjectType } from '../types'; +import { getSavedObjectType } from '../get_saved_object_type'; + +export const getSavedObjectTypes = ({ + namespaceType, +}: { + namespaceType: NamespaceTypeArray; +}): SavedObjectType[] => { + return namespaceType.map((singleNamespaceType) => + getSavedObjectType({ namespaceType: singleNamespaceType }) + ); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/has_large_value_list/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/has_large_value_list/index.ts new file mode 100644 index 0000000000000..350cb581153b5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/has_large_value_list/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EntriesArray } from '@kbn/securitysolution-io-ts-list-types'; + +export const hasLargeValueList = (entries: EntriesArray): boolean => { + const found = entries.filter(({ type }) => type === 'list'); + return found.length > 0; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts new file mode 100644 index 0000000000000..fe75ad88e0129 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/helpers/index.test.ts @@ -0,0 +1,375 @@ +/* + * 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 { + getMappingConflictsInfo, + fieldSupportsMatches, + hasWrongOperatorWithWildcard, + hasPartialCodeSignatureEntry, +} from '.'; + +describe('Helpers', () => { + describe('getMappingConflictsInfo', () => { + test('it return null if there are not conflicts', () => { + const field = { + name: 'field1', + type: 'string', + }; + const conflictsInfo = getMappingConflictsInfo(field); + + expect(conflictsInfo).toBeNull(); + }); + test('it groups ".ds-" data stream indices', () => { + const field = { + name: 'field1', + type: 'conflict', + conflictDescriptions: { + text: [ + '.ds-logs-default-2023.01.18-000001', + '.ds-logs-default-2023.01.18-000002', + '.ds-logs-tortilla.process-default-2022.11.20-000011', + '.ds-logs-tortilla.process-default-2022.11.20-000012', + '.ds-logs-tortilla.process-default-2022.11.20-000016', + ], + long: [ + '.ds-logs-default-2023.01.18-000004', + '.ds-logs-default-2023.01.18-000005', + 'partial-.ds-logs-gcp.audit-2021.12.22-000240', + 'partial-.ds-logs-gcp.audit-2021.12.22-000242', + ], + }, + }; + const conflictsInfo = getMappingConflictsInfo(field); + + expect(conflictsInfo).toEqual([ + { + type: 'text', + totalIndexCount: 5, + groupedIndices: [ + { name: 'logs-tortilla.process-default', count: 3 }, + { name: 'logs-default', count: 2 }, + ], + }, + { + type: 'long', + totalIndexCount: 4, + groupedIndices: [ + { name: 'logs-default', count: 2 }, + { name: 'logs-gcp.audit', count: 2 }, + ], + }, + ]); + }); + test('it groups old ".siem-" indices', () => { + const field = { + name: 'field1', + type: 'conflict', + conflictDescriptions: { + text: [ + '.siem-signals-default-000001', + '.siem-signals-default-000002', + '.siem-signals-default-000011', + '.siem-signals-default-000012', + ], + unmapped: [ + '.siem-signals-default-000004', + '.siem-signals-default-000005', + '.siem-signals-default-000240', + ], + }, + }; + const conflictsInfo = getMappingConflictsInfo(field); + + expect(conflictsInfo).toEqual([ + { + type: 'text', + totalIndexCount: 4, + groupedIndices: [{ name: '.siem-signals-default', count: 4 }], + }, + { + type: 'unmapped', + totalIndexCount: 3, + groupedIndices: [{ name: '.siem-signals-default', count: 3 }], + }, + ]); + }); + test('it groups mixed indices', () => { + const field = { + name: 'field1', + type: 'conflict', + conflictDescriptions: { + boolean: [ + '.ds-logs-default-2023.01.18-000001', + '.ds-logs-tortilla.process-default-2022.11.20-000011', + '.ds-logs-tortilla.process-default-2022.11.20-000012', + '.ds-logs-tortilla.process-default-2022.11.20-000016', + '.siem-signals-default-000001', + '.siem-signals-default-000002', + '.siem-signals-default-000012', + 'my-own-index-1', + 'my-own-index-2', + ], + unmapped: [ + '.siem-signals-default-000004', + 'partial-.ds-logs-gcp.audit-2021.12.22-000240', + 'partial-.ds-logs-gcp.audit-2021.12.22-000242', + 'my-own-index-3', + ], + }, + }; + const conflictsInfo = getMappingConflictsInfo(field); + + expect(conflictsInfo).toEqual([ + { + type: 'boolean', + totalIndexCount: 9, + groupedIndices: [ + { name: 'logs-tortilla.process-default', count: 3 }, + { name: '.siem-signals-default', count: 3 }, + { name: 'logs-default', count: 1 }, + { name: 'my-own-index-1', count: 1 }, + { name: 'my-own-index-2', count: 1 }, + ], + }, + { + type: 'unmapped', + totalIndexCount: 4, + groupedIndices: [ + { name: 'logs-gcp.audit', count: 2 }, + { name: '.siem-signals-default', count: 1 }, + { name: 'my-own-index-3', count: 1 }, + ], + }, + ]); + }); + }); + + describe('fieldSupportsMatches', () => { + test('it returns true if esTypes is keyword', () => { + expect( + fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['keyword'] }) + ).toBeTruthy(); + }); + + test('it returns true if one of the esTypes is kibana type string and another is not', () => { + expect( + fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['keyword', 'object'] }) + ).toBeTruthy(); + }); + + test('it returns true if one of the esTypes is keyword', () => { + expect( + fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['keyword', 'unmapped'] }) + ).toBeTruthy(); + }); + + test('it returns true if one of the esTypes is text', () => { + expect( + fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['text', 'unmapped'] }) + ).toBeTruthy(); + }); + + test('it returns true if all of the esTypes is map to kibana type string', () => { + expect( + fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['text', 'keyword'] }) + ).toBeTruthy(); + }); + + test('it returns false if none of the esTypes map to kibana type string', () => { + expect( + fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['bool', 'unmapped'] }) + ).toBeFalsy(); + }); + }); + describe('hasWrongOperatorWithWildcard', () => { + test('it returns true if there is at least one exception entry with a wildcard and the wrong operator', () => { + expect( + hasWrongOperatorWithWildcard([ + { + description: '', + name: '', + type: 'simple', + entries: [{ type: 'match', value: 'withwildcard*', field: '', operator: 'included' }], + }, + ]) + ).toBeTruthy(); + expect( + hasWrongOperatorWithWildcard([ + { + description: '', + name: '', + type: 'simple', + entries: [{ type: 'match', value: 'withwildcard?', field: '', operator: 'included' }], + }, + ]) + ).toBeTruthy(); + }); + + test('it returns true if there are entries joined with an OR that have a wildcard and the wrong operator', () => { + expect( + hasWrongOperatorWithWildcard([ + { + description: '', + name: '', + type: 'simple', + entries: [{ type: 'match', value: 'withwildcard?', field: '', operator: 'included' }], + }, + { + description: '', + name: '', + type: 'simple', + entries: [{ type: 'match', value: 'withwildcard?*', field: '', operator: 'included' }], + }, + ]) + ).toBeTruthy(); + }); + + test('it returns false if there are no exception entries with a wildcard and the wrong operator', () => { + expect( + hasWrongOperatorWithWildcard([ + { + description: '', + name: '', + type: 'simple', + entries: [ + { type: 'match', value: 'nowildcard', field: '', operator: 'excluded' }, + { type: 'wildcard', value: 'withwildcard*?', field: '', operator: 'included' }, + ], + }, + ]) + ).toBeFalsy(); + }); + + test('it returns true if there are nested entries with a wildcard and the wrong operator', () => { + expect( + hasWrongOperatorWithWildcard([ + { + description: '', + name: '', + type: 'simple', + entries: [ + { type: 'match', value: 'nowildcard', field: '', operator: 'excluded' }, + { + field: '', + type: 'nested', + entries: [{ type: 'match', value: 'wildcard?', field: '', operator: 'excluded' }], + }, + ], + }, + ]) + ).toBeTruthy(); + }); + }); + + describe('hasPartialCodeSignatureEntry', () => { + it('returns false if the entry has neither code signature subject name nor trusted field', () => { + expect( + hasPartialCodeSignatureEntry([ + { + description: '', + name: '', + type: 'simple', + os_types: ['windows'], + entries: [{ type: 'match', value: 'asdf', field: 'someField', operator: 'excluded' }], + }, + ]) + ).toBeFalsy(); + }); + it('returns true if the entry has code signature subject name but not trusted field', () => { + expect( + hasPartialCodeSignatureEntry([ + { + description: '', + name: '', + type: 'simple', + os_types: ['windows'], + entries: [ + { + type: 'match', + value: 'asdf', + field: 'process.code_signature.subject_name', + operator: 'excluded', + }, + ], + }, + ]) + ).toBeTruthy(); + }); + it('returns true if the entry has code signature trusted but not the subject name field', () => { + expect( + hasPartialCodeSignatureEntry([ + { + description: '', + name: '', + type: 'simple', + os_types: ['windows'], + entries: [ + { + type: 'match', + value: 'asdf', + field: 'process.code_signature.trusted', + operator: 'excluded', + }, + ], + }, + ]) + ).toBeTruthy(); + }); + it('returns false if the entry has both code signature subject name and trusted field', () => { + expect( + hasPartialCodeSignatureEntry([ + { + description: '', + name: '', + type: 'simple', + os_types: ['windows'], + entries: [ + { + type: 'match', + value: 'asdf', + field: 'process.code_signature.subject_name', + operator: 'excluded', + }, + { + type: 'match', + value: 'true', + field: 'process.code_signature.trusted', + operator: 'excluded', + }, + ], + }, + ]) + ).toBeFalsy(); + }); + it('returns false if the entry has both code signature team_id and trusted fields for mac os', () => { + expect( + hasPartialCodeSignatureEntry([ + { + description: '', + name: '', + type: 'simple', + os_types: ['macos'], + entries: [ + { + type: 'match', + value: 'asdf', + field: 'process.code_signature.team_id', + operator: 'excluded', + }, + { + type: 'match', + value: 'true', + field: 'process.code_signature.trusted', + operator: 'excluded', + }, + ], + }, + ]) + ).toBeFalsy(); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/helpers/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/helpers/index.ts new file mode 100644 index 0000000000000..6cbdbe55cfeb6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/helpers/index.ts @@ -0,0 +1,1088 @@ +/* + * 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 { v4 as uuidv4 } from 'uuid'; +import { + addIdToItem, + removeIdFromItem, + validateHasWildcardWithWrongOperator, +} from '@kbn/securitysolution-utils'; +import { validate } from '@kbn/securitysolution-io-ts-utils'; +import { + CreateExceptionListItemSchema, + EntriesArray, + Entry, + EntryNested, + ExceptionListType, + ListSchema, + NamespaceType, + ListOperatorEnum as OperatorEnum, + ListOperatorTypeEnum as OperatorTypeEnum, + createExceptionListItemSchema, + entriesList, + entriesNested, + entry, + exceptionListItemSchema, + nestedEntryItem, + CreateRuleExceptionListItemSchema, + createRuleExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { + DataViewBase, + DataViewFieldBase, + getDataViewFieldSubtypeNested, + isDataViewFieldSubtypeNested, +} from '@kbn/es-query'; +import { castEsToKbnFieldTypeName, KBN_FIELD_TYPES } from '@kbn/field-types'; + +import { + ALL_OPERATORS, + EXCEPTION_OPERATORS_SANS_LISTS, + doesNotExistOperator, + existsOperator, + isNotOperator, + isOneOfOperator, + isOperator, + DETECTION_ENGINE_EXCEPTION_OPERATORS, + isNotOneOfOperator, + isInListOperator, + isNotInListOperator, + matchesOperator, + doesNotMatchOperator, +} from '../autocomplete_operators'; + +import { + BuilderEntry, + CreateExceptionListItemBuilderSchema, + DataViewField, + EmptyEntry, + EmptyNestedEntry, + ExceptionsBuilderExceptionItem, + ExceptionsBuilderReturnExceptionItem, + FormattedBuilderEntry, + OperatorOption, + SavedObjectType, +} from '../types'; + +export const isEntryNested = (item: BuilderEntry): item is EntryNested => { + return (item as EntryNested).entries != null; +}; + +export const filterExceptionItems = ( + exceptions: ExceptionsBuilderExceptionItem[] +): ExceptionsBuilderReturnExceptionItem[] => { + return exceptions.reduce((acc, exception) => { + const entries = exception.entries.reduce((nestedAcc, singleEntry) => { + const strippedSingleEntry = removeIdFromItem(singleEntry); + if (entriesNested.is(strippedSingleEntry)) { + const nestedEntriesArray = strippedSingleEntry.entries.filter((singleNestedEntry) => { + const noIdSingleNestedEntry = removeIdFromItem(singleNestedEntry); + const [validatedNestedEntry] = validate(noIdSingleNestedEntry, nestedEntryItem); + return validatedNestedEntry != null; + }); + const noIdNestedEntries = nestedEntriesArray.map((singleNestedEntry) => + removeIdFromItem(singleNestedEntry) + ); + + const [validatedNestedEntry] = validate( + { ...strippedSingleEntry, entries: noIdNestedEntries }, + entriesNested + ); + + if (validatedNestedEntry != null) { + return [...nestedAcc, { ...singleEntry, entries: nestedEntriesArray }]; + } + return nestedAcc; + } else { + const [validatedEntry] = validate(strippedSingleEntry, entry); + if (validatedEntry != null) { + return [...nestedAcc, singleEntry]; + } + return nestedAcc; + } + }, []); + + if (entries.length === 0) { + return acc; + } + + const item = { ...exception, entries }; + + if (exceptionListItemSchema.is(item)) { + return [...acc, item]; + } else if ( + createExceptionListItemSchema.is(item) || + createRuleExceptionListItemSchema.is(item) + ) { + const { meta, ...rest } = item; + const itemSansMetaId: CreateExceptionListItemSchema | CreateRuleExceptionListItemSchema = { + ...rest, + meta: undefined, + }; + return [...acc, itemSansMetaId]; + } else { + return acc; + } + }, []); +}; + +export const addIdToEntries = (entries: EntriesArray): EntriesArray => { + return entries.map((singleEntry) => { + if (singleEntry.type === 'nested') { + return addIdToItem({ + ...singleEntry, + entries: singleEntry.entries.map((nestedEntry) => addIdToItem(nestedEntry)), + }); + } else { + return addIdToItem(singleEntry); + } + }); +}; + +export const getNewExceptionItem = ({ + listId, + namespaceType, + name, +}: { + listId: string | undefined; + namespaceType: NamespaceType | undefined; + name: string; +}): CreateExceptionListItemBuilderSchema => { + return { + comments: [], + description: `Exception list item`, + entries: addIdToEntries([ + { + field: '', + operator: 'included', + type: 'match', + value: '', + }, + ]), + item_id: undefined, + list_id: listId, + meta: { + temporaryUuid: uuidv4(), + }, + name, + namespace_type: namespaceType, + tags: [], + type: 'simple', + }; +}; + +/** + * Returns the operator type, may not need this if using io-ts types + * + * @param item a single ExceptionItem entry + */ +export const getOperatorType = (item: BuilderEntry): OperatorTypeEnum => { + switch (item.type) { + case 'match': + return OperatorTypeEnum.MATCH; + case 'match_any': + return OperatorTypeEnum.MATCH_ANY; + case 'wildcard': + return OperatorTypeEnum.WILDCARD; + case 'list': + return OperatorTypeEnum.LIST; + default: + return OperatorTypeEnum.EXISTS; + } +}; + +/** + * Determines operator selection (is/is not/is one of, etc.) + * Default operator is "is" + * + * @param item a single ExceptionItem entry + */ +export const getExceptionOperatorSelect = (item: BuilderEntry): OperatorOption => { + if (item.type === 'nested') { + return isOperator; + } else { + const operatorType = getOperatorType(item); + const foundOperator = ALL_OPERATORS.find((operatorOption) => { + return item.operator === operatorOption.operator && operatorType === operatorOption.type; + }); + + return foundOperator != null ? foundOperator : isOperator; + } +}; + +/** + * Returns the fields corresponding value for an entry + * + * @param item a single ExceptionItem entry + */ +export const getEntryValue = (item: BuilderEntry): string | string[] | undefined => { + switch (item.type) { + case OperatorTypeEnum.MATCH: + case OperatorTypeEnum.MATCH_ANY: + case OperatorTypeEnum.WILDCARD: + return item.value; + case OperatorTypeEnum.EXISTS: + return undefined; + case OperatorTypeEnum.LIST: + return item.list.id; + default: + return undefined; + } +}; + +/** + * Determines whether an entire entry, exception item, or entry within a nested + * entry needs to be removed + * + * @param exceptionItem + * @param entryIndex index of given entry, for nested entries, this will correspond + * to their parent index + * @param nestedEntryIndex index of nested entry + * + */ +export const getUpdatedEntriesOnDelete = ( + exceptionItem: ExceptionsBuilderExceptionItem, + entryIndex: number, + nestedParentIndex: number | null +): ExceptionsBuilderExceptionItem => { + const itemOfInterest: BuilderEntry = + exceptionItem.entries[nestedParentIndex != null ? nestedParentIndex : entryIndex]; + + if (nestedParentIndex != null && itemOfInterest.type === OperatorTypeEnum.NESTED) { + const updatedEntryEntries = [ + ...itemOfInterest.entries.slice(0, entryIndex), + ...itemOfInterest.entries.slice(entryIndex + 1), + ]; + + if (updatedEntryEntries.length === 0) { + return { + ...exceptionItem, + entries: [ + ...exceptionItem.entries.slice(0, nestedParentIndex), + ...exceptionItem.entries.slice(nestedParentIndex + 1), + ], + }; + } else { + const { field } = itemOfInterest; + const updatedItemOfInterest: EntryNested | EmptyNestedEntry = { + entries: updatedEntryEntries, + field, + id: itemOfInterest.id != null ? itemOfInterest.id : `${entryIndex}`, + type: OperatorTypeEnum.NESTED, + }; + + return { + ...exceptionItem, + entries: [ + ...exceptionItem.entries.slice(0, nestedParentIndex), + updatedItemOfInterest, + ...exceptionItem.entries.slice(nestedParentIndex + 1), + ], + }; + } + } else { + return { + ...exceptionItem, + entries: [ + ...exceptionItem.entries.slice(0, entryIndex), + ...exceptionItem.entries.slice(entryIndex + 1), + ], + }; + } +}; + +/** + * Returns filtered index patterns based on the field - if a user selects to + * add nested entry, should only show nested fields, if item is the parent + * field of a nested entry, we only display the parent field + * + * @param patterns DataViewBase containing available fields on rule index + * @param item exception item entry + * set to add a nested field + */ +export const getFilteredIndexPatterns = ( + patterns: DataViewBase, + item: FormattedBuilderEntry +): DataViewBase => { + if (item.nested === 'child' && item.parent != null) { + // when user has selected a nested entry, only fields with the common parent are shown + return { + ...patterns, + fields: patterns.fields + .filter((indexField) => { + const subTypeNested = getDataViewFieldSubtypeNested(indexField); + const fieldHasCommonParentPath = + subTypeNested && + item.parent != null && + subTypeNested.nested.path === item.parent.parent.field; + + return fieldHasCommonParentPath; + }) + .map((f) => { + const [fieldNameWithoutParentPath] = f.name.split('.').slice(-1); + return { ...f, name: fieldNameWithoutParentPath }; + }), + }; + } else if (item.nested === 'parent' && item.field != null) { + // when user has selected a nested entry, right above it we show the common parent + return { ...patterns, fields: [item.field] }; + } else if (item.nested === 'parent' && item.field == null) { + // when user selects to add a nested entry, only nested fields are shown as options + return { + ...patterns, + fields: patterns.fields.filter((field) => isDataViewFieldSubtypeNested(field)), + }; + } else { + return patterns; + } +}; + +/** + * Determines proper entry update when user selects new field + * + * @param item - current exception item entry values + * @param newField - newly selected field + * + */ +export const getEntryOnFieldChange = ( + item: FormattedBuilderEntry, + newField: DataViewFieldBase +): { index: number; updatedEntry: BuilderEntry } => { + const { parent, entryIndex, nested } = item; + const newChildFieldValue = newField != null ? newField.name.split('.').slice(-1)[0] : ''; + + if (nested === 'parent') { + // For nested entries, when user first selects to add a nested + // entry, they first see a row similar to what is shown for when + // a user selects "exists", as soon as they make a selection + // we can now identify the 'parent' and 'child' this is where + // we first convert the entry into type "nested" + const subTypeNested = getDataViewFieldSubtypeNested(newField); + const newParentFieldValue = subTypeNested?.nested.path || ''; + + return { + index: entryIndex, + updatedEntry: { + entries: [ + addIdToItem({ + field: newChildFieldValue != null ? newChildFieldValue : '', + operator: isOperator.operator, + type: OperatorTypeEnum.MATCH, + value: '', + }), + ], + field: newParentFieldValue, + id: item.id, + type: OperatorTypeEnum.NESTED, + }, + }; + } else if (nested === 'child' && parent != null) { + return { + index: parent.parentIndex, + updatedEntry: { + ...parent.parent, + entries: [ + ...parent.parent.entries.slice(0, entryIndex), + { + field: newChildFieldValue != null ? newChildFieldValue : '', + id: item.id, + operator: isOperator.operator, + type: OperatorTypeEnum.MATCH, + value: '', + }, + ...parent.parent.entries.slice(entryIndex + 1), + ], + }, + }; + } else { + return { + index: entryIndex, + updatedEntry: { + field: newField != null ? newField.name : '', + id: item.id, + operator: isOperator.operator, + type: OperatorTypeEnum.MATCH, + value: '', + }, + }; + } +}; + +/** + * Determines proper entry update when user updates value + * when operator is of type "list" + * + * @param item - current exception item entry values + * @param newField - newly selected list + * + */ +export const getEntryOnListChange = ( + item: FormattedBuilderEntry, + newField: ListSchema +): { index: number; updatedEntry: BuilderEntry } => { + const { entryIndex, field, operator } = item; + const { id, type } = newField; + + return { + index: entryIndex, + updatedEntry: { + field: field != null ? field.name : '', + id: item.id, + list: { id, type }, + operator: operator.operator, + type: OperatorTypeEnum.LIST, + }, + }; +}; + +/** + * Determines proper entry update when user updates value + * when operator is of type "match_any" + * + * @param item - current exception item entry values + * @param newField - newly entered value + * + */ +export const getEntryOnMatchAnyChange = ( + item: FormattedBuilderEntry, + newField: string[] +): { index: number; updatedEntry: BuilderEntry } => { + const { nested, parent, entryIndex, field, operator } = item; + + if (nested != null && parent != null) { + const fieldName = field != null ? field.name.split('.').slice(-1)[0] : ''; + + return { + index: parent.parentIndex, + updatedEntry: { + ...parent.parent, + entries: [ + ...parent.parent.entries.slice(0, entryIndex), + { + field: fieldName, + id: item.id, + operator: operator.operator, + type: OperatorTypeEnum.MATCH_ANY, + value: newField, + }, + ...parent.parent.entries.slice(entryIndex + 1), + ], + }, + }; + } else { + return { + index: entryIndex, + updatedEntry: { + field: field != null ? field.name : '', + id: item.id, + operator: operator.operator, + type: OperatorTypeEnum.MATCH_ANY, + value: newField, + }, + }; + } +}; + +/** + * Determines proper entry update when user updates value + * when operator is of type "match" + * + * @param item - current exception item entry values + * @param newField - newly entered value + * + */ +export const getEntryOnMatchChange = ( + item: FormattedBuilderEntry, + newField: string +): { index: number; updatedEntry: BuilderEntry } => { + const { nested, parent, entryIndex, field, operator } = item; + + if (nested != null && parent != null) { + const fieldName = field != null ? field.name.split('.').slice(-1)[0] : ''; + + return { + index: parent.parentIndex, + updatedEntry: { + ...parent.parent, + entries: [ + ...parent.parent.entries.slice(0, entryIndex), + { + field: fieldName, + id: item.id, + operator: operator.operator, + type: OperatorTypeEnum.MATCH, + value: newField, + }, + ...parent.parent.entries.slice(entryIndex + 1), + ], + }, + }; + } else { + return { + index: entryIndex, + updatedEntry: { + field: field != null ? field.name : '', + id: item.id, + operator: operator.operator, + type: OperatorTypeEnum.MATCH, + value: newField, + }, + }; + } +}; + +/** + * Determines proper entry update when user updates value + * when operator is of type "wildcard" + * + * @param item - current exception item entry values + * @param newField - newly entered value + * + */ +export const getEntryOnWildcardChange = ( + item: FormattedBuilderEntry, + newField: string +): { index: number; updatedEntry: BuilderEntry } => { + const { nested, parent, entryIndex, field, operator } = item; + + if (nested != null && parent != null) { + const fieldName = field != null ? field.name.split('.').slice(-1)[0] : ''; + + return { + index: parent.parentIndex, + updatedEntry: { + ...parent.parent, + entries: [ + ...parent.parent.entries.slice(0, entryIndex), + { + field: fieldName, + id: item.id, + operator: operator.operator, + type: OperatorTypeEnum.WILDCARD, + value: newField, + }, + ...parent.parent.entries.slice(entryIndex + 1), + ], + }, + }; + } else { + return { + index: entryIndex, + updatedEntry: { + field: field != null ? field.name : '', + id: item.id, + operator: operator.operator, + type: OperatorTypeEnum.WILDCARD, + value: newField, + }, + }; + } +}; + +/** + * On operator change, determines whether value needs to be cleared or not + * + * @param field + * @param selectedOperator + * @param currentEntry + * + */ +export const getEntryFromOperator = ( + selectedOperator: OperatorOption, + currentEntry: FormattedBuilderEntry +): Entry & { id?: string } => { + const isSameOperatorType = currentEntry.operator.type === selectedOperator.type; + const fieldValue = currentEntry.field != null ? currentEntry.field.name : ''; + switch (selectedOperator.type) { + case 'match': + return { + field: fieldValue, + id: currentEntry.id, + operator: selectedOperator.operator, + type: OperatorTypeEnum.MATCH, + value: + isSameOperatorType && typeof currentEntry.value === 'string' ? currentEntry.value : '', + }; + case 'match_any': + return { + field: fieldValue, + id: currentEntry.id, + operator: selectedOperator.operator, + type: OperatorTypeEnum.MATCH_ANY, + value: isSameOperatorType && Array.isArray(currentEntry.value) ? currentEntry.value : [], + }; + case 'list': + return { + field: fieldValue, + id: currentEntry.id, + list: { id: '', type: 'ip' }, + operator: selectedOperator.operator, + type: OperatorTypeEnum.LIST, + }; + case 'wildcard': + return { + field: fieldValue, + id: currentEntry.id, + operator: selectedOperator.operator, + type: OperatorTypeEnum.WILDCARD, + value: + isSameOperatorType && typeof currentEntry.value === 'string' ? currentEntry.value : '', + }; + default: + return { + field: fieldValue, + id: currentEntry.id, + operator: selectedOperator.operator, + type: OperatorTypeEnum.EXISTS, + }; + } +}; + +/** + * Determines proper entry update when user selects new operator + * + * @param item - current exception item entry values + * @param newOperator - newly selected operator + * + */ +export const getEntryOnOperatorChange = ( + item: FormattedBuilderEntry, + newOperator: OperatorOption +): { updatedEntry: BuilderEntry; index: number } => { + const { parent, entryIndex, field, nested } = item; + const newEntry = getEntryFromOperator(newOperator, item); + + if (!entriesList.is(newEntry) && nested != null && parent != null) { + return { + index: parent.parentIndex, + updatedEntry: { + ...parent.parent, + entries: [ + ...parent.parent.entries.slice(0, entryIndex), + { + ...newEntry, + field: field != null ? field.name.split('.').slice(-1)[0] : '', + }, + ...parent.parent.entries.slice(entryIndex + 1), + ], + }, + }; + } else { + return { index: entryIndex, updatedEntry: newEntry }; + } +}; + +export const isKibanaStringType = (type: string) => { + const kbnFieldType = castEsToKbnFieldTypeName(type); + return kbnFieldType === KBN_FIELD_TYPES.STRING; +}; + +export const fieldSupportsMatches = (field: DataViewFieldBase) => { + return field.esTypes?.some(isKibanaStringType); +}; + +/** + * Determines which operators to make available + * + * @param item + * @param listType + * @param isBoolean + * @param includeValueListOperators whether or not to include the 'is in list' and 'is not in list' operators + */ +export const getOperatorOptions = ( + item: FormattedBuilderEntry, + listType: ExceptionListType, + isBoolean: boolean, + includeValueListOperators = true +): OperatorOption[] => { + if (item.nested === 'parent' || item.field == null) { + return [isOperator]; + } else if (listType === 'endpoint') { + if (isBoolean) { + return [isOperator]; + } else { + return fieldSupportsMatches(item.field) + ? [isOperator, isOneOfOperator, matchesOperator, doesNotMatchOperator] + : [isOperator, isOneOfOperator]; + } + } else if (item.nested != null && listType === 'detection') { + return isBoolean ? [isOperator, existsOperator] : [isOperator, isOneOfOperator, existsOperator]; + } else if (isBoolean) { + return [isOperator, isNotOperator, existsOperator, doesNotExistOperator]; + } else if (!includeValueListOperators) { + return fieldSupportsMatches(item.field) + ? EXCEPTION_OPERATORS_SANS_LISTS + : [ + isOperator, + isNotOperator, + isOneOfOperator, + isNotOneOfOperator, + existsOperator, + doesNotExistOperator, + ]; + } else { + return listType === 'detection' + ? fieldSupportsMatches(item.field) + ? DETECTION_ENGINE_EXCEPTION_OPERATORS + : [ + isOperator, + isNotOperator, + isOneOfOperator, + isNotOneOfOperator, + existsOperator, + doesNotExistOperator, + isInListOperator, + isNotInListOperator, + ] + : ALL_OPERATORS; + } +}; + +/** + * Fields of type 'text' do not generate autocomplete values, we want + * to find it's corresponding keyword type (if available) which does + * generate autocomplete values + * + * @param fields DataViewFieldBase fields + * @param selectedField the field name that was selected + * @param isTextType we only want a corresponding keyword field if + * the selected field is of type 'text' + * + */ +export const getCorrespondingKeywordField = ({ + fields, + selectedField, +}: { + fields: DataViewFieldBase[]; + selectedField: string | undefined; +}): DataViewFieldBase | undefined => { + const selectedFieldBits = + selectedField != null && selectedField !== '' ? selectedField.split('.') : []; + const selectedFieldIsTextType = selectedFieldBits.slice(-1)[0] === 'text'; + + if (selectedFieldIsTextType && selectedFieldBits.length > 0) { + const keywordField = selectedFieldBits.slice(0, selectedFieldBits.length - 1).join('.'); + const [foundKeywordField] = fields.filter( + ({ name }) => keywordField !== '' && keywordField === name + ); + return foundKeywordField; + } + + return undefined; +}; + +/** + * Formats the entry into one that is easily usable for the UI, most of the + * complexity was introduced with nested fields + * + * @param patterns DataViewBase containing available fields on rule index + * @param item exception item entry + * @param itemIndex entry index + * @param parent nested entries hold copy of their parent for use in various logic + * @param parentIndex corresponds to the entry index, this might seem obvious, but + * was added to ensure that nested items could be identified with their parent entry + * @param allowCustomFieldOptions determines if field must be found to match in indexPattern or not + */ +export const getFormattedBuilderEntry = ( + indexPattern: DataViewBase, + item: BuilderEntry, + itemIndex: number, + parent: EntryNested | undefined, + parentIndex: number | undefined, + allowCustomFieldOptions: boolean +): FormattedBuilderEntry => { + const { fields } = indexPattern; + const field = parent != null ? `${parent.field}.${item.field}` : item.field; + const [foundField] = fields.filter(({ name }) => field != null && field === name); + const correspondingKeywordField = getCorrespondingKeywordField({ + fields, + selectedField: field, + }); + + if (parent != null && parentIndex != null) { + return { + correspondingKeywordField, + entryIndex: itemIndex, + field: + foundField != null + ? { ...foundField, name: foundField.name.split('.').slice(-1)[0] } + : foundField, + id: item.id != null ? item.id : `${itemIndex}`, + nested: 'child', + operator: getExceptionOperatorSelect(item), + parent: { parent, parentIndex }, + value: getEntryValue(item), + }; + } else { + const fieldToUse = allowCustomFieldOptions + ? foundField ?? { name: item.field, type: 'keyword' } + : foundField; + + return { + correspondingKeywordField, + entryIndex: itemIndex, + field: fieldToUse, + id: item.id != null ? item.id : `${itemIndex}`, + nested: undefined, + operator: getExceptionOperatorSelect(item), + parent: undefined, + value: getEntryValue(item), + }; + } +}; + +/** + * Formats the entries to be easily usable for the UI, most of the + * complexity was introduced with nested fields + * + * @param patterns DataViewBase containing available fields on rule index + * @param entries exception item entries + * @param allowCustomFieldOptions determines if field must be found to match in indexPattern or not + * @param parent nested entries hold copy of their parent for use in various logic + * @param parentIndex corresponds to the entry index, this might seem obvious, but + * was added to ensure that nested items could be identified with their parent entry + */ +export const getFormattedBuilderEntries = ( + indexPattern: DataViewBase, + entries: BuilderEntry[], + allowCustomFieldOptions: boolean, + parent?: EntryNested, + parentIndex?: number +): FormattedBuilderEntry[] => { + return entries.reduce((acc, item, index) => { + const isNewNestedEntry = item.type === 'nested' && item.entries.length === 0; + if (item.type !== 'nested' && !isNewNestedEntry) { + const newItemEntry: FormattedBuilderEntry = getFormattedBuilderEntry( + indexPattern, + item, + index, + parent, + parentIndex, + allowCustomFieldOptions + ); + return [...acc, newItemEntry]; + } else { + const parentEntry: FormattedBuilderEntry = { + correspondingKeywordField: undefined, + entryIndex: index, + field: isNewNestedEntry + ? undefined + : // This type below is really a FieldSpec type from "src/plugins/data/common/index_patterns/fields/types.ts", we cast it here to keep using the DataViewFieldBase interface + ({ + aggregatable: false, + esTypes: ['nested'], + name: item.field != null ? item.field : '', + searchable: false, + type: 'string', + } as DataViewFieldBase), + id: item.id != null ? item.id : `${index}`, + nested: 'parent', + operator: isOperator, + parent: undefined, + value: undefined, + }; + + // User has selected to add a nested field, but not yet selected the field + if (isNewNestedEntry) { + return [...acc, parentEntry]; + } + + if (isEntryNested(item)) { + const nestedItems = getFormattedBuilderEntries( + indexPattern, + item.entries, + allowCustomFieldOptions, + item, + index + ); + + return [...acc, parentEntry, ...nestedItems]; + } + + return [...acc]; + } + }, []); +}; + +export const getDefaultEmptyEntry = (): EmptyEntry => ({ + field: '', + id: uuidv4(), + operator: OperatorEnum.INCLUDED, + type: OperatorTypeEnum.MATCH, + value: '', +}); + +export const getDefaultNestedEmptyEntry = (): EmptyNestedEntry => ({ + entries: [], + field: '', + id: uuidv4(), + type: OperatorTypeEnum.NESTED, +}); + +export const containsValueListEntry = (items: ExceptionsBuilderExceptionItem[]): boolean => + items.some((item) => item.entries.some(({ type }) => type === OperatorTypeEnum.LIST)); + +export const buildShowActiveExceptionsFilter = (savedObjectPrefix: SavedObjectType[]): string => { + const now = new Date().toISOString(); + const filters = savedObjectPrefix.map( + (prefix) => + `${prefix}.attributes.expire_time > "${now}" OR NOT ${prefix}.attributes.expire_time: *` + ); + return filters.join(','); +}; + +export const buildShowExpiredExceptionsFilter = (savedObjectPrefix: SavedObjectType[]): string => { + const now = new Date().toISOString(); + const filters = savedObjectPrefix.map((prefix) => `${prefix}.attributes.expire_time <= "${now}"`); + return filters.join(','); +}; + +const getIndexGroupName = (indexName: string): string => { + // Check whether it is a Data Stream index + const dataStreamExp = /.ds-(.*?)-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-[0-9]{6}/; + let result = indexName.match(dataStreamExp); + if (result && result.length === 2) { + return result[1]; + } + + // Check whether it is an old '.siem' index group + const siemSignalsExp = /.siem-(.*?)-[0-9]{6}/; + result = indexName.match(siemSignalsExp); + if (result && result.length === 2) { + return `.siem-${result[1]}`; + } + + // Otherwise return index name + return indexName; +}; + +export interface FieldConflictsInfo { + /** + * Kibana field type + */ + type: string; + /** + * Total count of the indices of this type + */ + totalIndexCount: number; + /** + * Grouped indices info + */ + groupedIndices: Array<{ + /** + * Index group name (like '.ds-...' or '.siem-signals-...') + */ + name: string; + /** + * Count of indices in the group + */ + count: number; + }>; +} + +export const getMappingConflictsInfo = (field: DataViewField): FieldConflictsInfo[] | null => { + if (!field.conflictDescriptions) { + return null; + } + const conflicts: FieldConflictsInfo[] = []; + for (const [key, value] of Object.entries(field.conflictDescriptions)) { + const groupedIndices: Array<{ + name: string; + count: number; + }> = []; + + // Group indices and calculate count of indices in each group + const groupedInfo: { [key: string]: number } = {}; + value.forEach((index) => { + const groupName = getIndexGroupName(index); + if (!groupedInfo[groupName]) { + groupedInfo[groupName] = 0; + } + groupedInfo[groupName]++; + }); + for (const [name, count] of Object.entries(groupedInfo)) { + groupedIndices.push({ + name, + count, + }); + } + + // Sort groups by the indices count + groupedIndices.sort((group1, group2) => { + return group2.count - group1.count; + }); + + conflicts.push({ + type: key, + totalIndexCount: value.length, + groupedIndices, + }); + } + return conflicts; +}; + +/** + * Given an exceptions list, determine if any entries have an "IS" operator with a wildcard value + */ +export const hasWrongOperatorWithWildcard = ( + items: ExceptionsBuilderReturnExceptionItem[] +): boolean => { + // flattens array of multiple entries added with OR + const multipleEntries = items.flatMap((item) => item.entries); + // flattens nested entries + const allEntries = multipleEntries.flatMap((item) => { + if (item.type === 'nested') { + return item.entries; + } + return item; + }); + + // eslint-disable-next-line array-callback-return + return allEntries.some((e) => { + if (e.type !== 'list' && 'value' in e) { + return validateHasWildcardWithWrongOperator({ + operator: e.type, + value: e.value, + }); + } + }); +}; + +/** + * Event filters helper where given an exceptions list, + * determine if both 'subject_name' and 'trusted' are + * included in an entry with 'code_signature' + */ +export const hasPartialCodeSignatureEntry = ( + items: ExceptionsBuilderReturnExceptionItem[] +): boolean => { + const { os_types: os = ['windows'], entries = [] } = items[0] || {}; + let name = false; + let trusted = false; + + for (const e of entries) { + if (e.type === 'nested' && e.field === 'process.Ext.code_signature') { + const includesNestedName = e.entries.some( + (nestedEntry) => nestedEntry.field === 'subject_name' + ); + const includesNestedTrusted = e.entries.some( + (nestedEntry) => nestedEntry.field === 'trusted' + ); + if (includesNestedName !== includesNestedTrusted) { + return true; + } + } else if ( + e.field === 'process.code_signature.subject_name' || + (os.includes('macos') && e.field === 'process.code_signature.team_id') + ) { + name = true; + } else if (e.field === 'process.code_signature.trusted') { + trusted = true; + } + } + return name !== trusted; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/types/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/types/index.ts new file mode 100644 index 0000000000000..1730a0e9a8291 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/src/types/index.ts @@ -0,0 +1,122 @@ +/* + * 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 { DataViewFieldBase } from '@kbn/es-query'; +import type { + CreateExceptionListItemSchema, + CreateRuleExceptionListItemSchema, + Entry, + EntryExists, + EntryMatch, + EntryMatchAny, + EntryMatchWildcard, + EntryNested, + ExceptionListItemSchema, + ListOperatorEnum as OperatorEnum, + ListOperatorTypeEnum as OperatorTypeEnum, + NamespaceType, +} from '@kbn/securitysolution-io-ts-list-types'; +import { + EXCEPTION_LIST_NAMESPACE, + EXCEPTION_LIST_NAMESPACE_AGNOSTIC, +} from '@kbn/securitysolution-list-constants'; + +export interface DataViewField extends DataViewFieldBase { + conflictDescriptions?: Record; +} + +export interface OperatorOption { + message: string; + value: string; + operator: OperatorEnum; + type: OperatorTypeEnum; +} + +export interface FormattedBuilderEntry { + id: string; + field: DataViewField | undefined; + operator: OperatorOption; + value: string | string[] | undefined; + nested: 'parent' | 'child' | undefined; + entryIndex: number; + parent: { parent: BuilderEntryNested; parentIndex: number } | undefined; + correspondingKeywordField: DataViewFieldBase | undefined; +} + +export interface EmptyEntry { + id: string; + field: string | undefined; + operator: OperatorEnum; + type: OperatorTypeEnum.MATCH | OperatorTypeEnum.MATCH_ANY | OperatorTypeEnum.WILDCARD; + value: string | string[] | undefined; +} + +export interface EmptyListEntry { + id: string; + field: string | undefined; + operator: OperatorEnum; + type: OperatorTypeEnum.LIST; + list: { id: string | undefined; type: string | undefined }; +} + +export interface EmptyNestedEntry { + id: string; + field: string | undefined; + type: OperatorTypeEnum.NESTED; + entries: Array< + | (EntryMatch & { id?: string }) + | (EntryMatchAny & { id?: string }) + | (EntryMatchWildcard & { id?: string }) + | (EntryExists & { id?: string }) + >; +} + +export type BuilderEntry = + | (Entry & { id?: string }) + | EmptyListEntry + | EmptyEntry + | BuilderEntryNested + | EmptyNestedEntry; + +export type BuilderEntryNested = Omit & { + id?: string; + entries: Array< + | (EntryMatch & { id?: string }) + | (EntryMatchAny & { id?: string }) + | (EntryMatchWildcard & { id?: string }) + | (EntryExists & { id?: string }) + >; +}; + +export type ExceptionListItemBuilderSchema = Omit & { + entries: BuilderEntry[]; +}; + +export type CreateExceptionListItemBuilderSchema = Omit< + CreateExceptionListItemSchema, + 'meta' | 'entries' | 'list_id' | 'namespace_type' +> & { + meta: { temporaryUuid: string }; + entries: BuilderEntry[]; + list_id: string | undefined; + namespace_type: NamespaceType | undefined; +}; + +export type ExceptionsBuilderExceptionItem = + | ExceptionListItemBuilderSchema + | CreateExceptionListItemBuilderSchema; + +export type ExceptionsBuilderReturnExceptionItem = + | ExceptionListItemSchema + | CreateExceptionListItemSchema + | CreateRuleExceptionListItemSchema; + +export const exceptionListSavedObjectType = EXCEPTION_LIST_NAMESPACE; +export const exceptionListAgnosticSavedObjectType = EXCEPTION_LIST_NAMESPACE_AGNOSTIC; +export type SavedObjectType = + | typeof EXCEPTION_LIST_NAMESPACE + | typeof EXCEPTION_LIST_NAMESPACE_AGNOSTIC; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/tsconfig.json new file mode 100644 index 0000000000000..0b6eb353950df --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-list-utils/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "kbn_references": [ + "@kbn/es-query", + "@kbn/i18n", + "@kbn/securitysolution-io-ts-list-types", + "@kbn/securitysolution-io-ts-utils", + "@kbn/securitysolution-list-constants", + "@kbn/securitysolution-utils", + "@kbn/field-types" + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-lists-common/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/README.md similarity index 100% rename from packages/kbn-securitysolution-lists-common/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts new file mode 100644 index 0000000000000..cf603f3ac3bdb --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Create list API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { + ListId, + ListName, + ListDescription, + ListType, + ListMetadata, +} from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type CreateListRequestBody = z.infer; +export const CreateListRequestBody = z.object({ + id: ListId.optional(), + name: ListName, + description: ListDescription, + type: ListType, + serializer: z.string().optional(), + deserializer: z.string().optional(), + meta: ListMetadata.optional(), + version: z.number().int().min(1).optional().default(1), +}); +export type CreateListRequestBodyInput = z.input; + +export type CreateListResponse = z.infer; +export const CreateListResponse = List; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml new file mode 100644 index 0000000000000..df3e6b35ef65a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml @@ -0,0 +1,81 @@ +openapi: 3.0.0 +info: + title: Create list API endpoint + version: '2023-10-31' +paths: + /api/lists: + post: + x-labels: [serverless, ess] + operationId: CreateList + x-codegen-enabled: true + summary: Create a list + description: Create a new list. + requestBody: + description: List's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + name: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListName' + description: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListDescription' + type: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListType' + serializer: + type: string + deserializer: + type: string + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListMetadata' + version: + type: integer + minimum: 1 + default: 1 + required: + - name + - description + - type + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 409: + description: List already exists response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts new file mode 100644 index 0000000000000..7eb20ada7f322 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts @@ -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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Create list DS API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +export type CreateListIndexResponse = z.infer; +export const CreateListIndexResponse = z.object({ + acknowledged: z.boolean(), +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml new file mode 100644 index 0000000000000..8ff9ad6ab1b2e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml @@ -0,0 +1,55 @@ +openapi: 3.0.0 +info: + title: Create list DS API endpoint + version: '2023-10-31' +paths: + /api/lists/index: + post: + x-labels: [serverless, ess] + operationId: CreateListIndex + x-codegen-enabled: true + summary: Create list data streams + description: Create `.lists` and `.items` data streams in the relevant space. + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: [acknowledged] + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 409: + description: List data stream exists response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts new file mode 100644 index 0000000000000..ce4744f3c4418 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Create list item API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { ListItemId, ListId, ListItemValue, ListItemMetadata } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type CreateListItemRequestBody = z.infer; +export const CreateListItemRequestBody = z.object({ + id: ListItemId.optional(), + list_id: ListId, + value: ListItemValue, + meta: ListItemMetadata.optional(), + /** + * Determines when changes made by the request are made visible to search + */ + refresh: z.enum(['true', 'false', 'wait_for']).optional(), +}); +export type CreateListItemRequestBodyInput = z.input; + +export type CreateListItemResponse = z.infer; +export const CreateListItemResponse = ListItem; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml new file mode 100644 index 0000000000000..01d024f8b40d8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml @@ -0,0 +1,82 @@ +openapi: 3.0.0 +info: + title: Create list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + post: + x-labels: [serverless, ess] + operationId: CreateListItem + x-codegen-enabled: true + summary: Create a list item + description: | + Create a list item and associate it with the specified list. + + All list items in the same list must be the same type. For example, each list item in an `ip` list must define a specific IP address. + > info + > Before creating a list item, you must create a list. + requestBody: + description: List item's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemId' + list_id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + value: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemValue' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemMetadata' + refresh: + type: string + enum: + - 'true' + - 'false' + - wait_for + description: Determines when changes made by the request are made visible to search + required: + - list_id + - value + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 409: + description: List item already exists response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.ts new file mode 100644 index 0000000000000..3dd638be564ee --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.ts @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Delete list API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; +import { BooleanFromString } from '@kbn/zod-helpers'; + +import { ListId } from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type DeleteListRequestQuery = z.infer; +export const DeleteListRequestQuery = z.object({ + /** + * List's `id` value + */ + id: ListId, + deleteReferences: BooleanFromString.optional().default(false), + ignoreReferences: BooleanFromString.optional().default(false), +}); +export type DeleteListRequestQueryInput = z.input; + +export type DeleteListResponse = z.infer; +export const DeleteListResponse = List; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml new file mode 100644 index 0000000000000..e8caef0eb2c6c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml @@ -0,0 +1,73 @@ +openapi: 3.0.0 +info: + title: Delete list API endpoint + version: '2023-10-31' +paths: + /api/lists: + delete: + x-labels: [serverless, ess] + operationId: DeleteList + x-codegen-enabled: true + summary: Delete a list + description: | + Delete a list using the list ID. + > info + > When you delete a list, all of its list items are also deleted. + parameters: + - name: id + in: query + required: true + description: List's `id` value + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: deleteReferences + in: query + required: false + schema: + type: boolean + default: false + - name: ignoreReferences + in: query + required: false + schema: + type: boolean + default: false + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts new file mode 100644 index 0000000000000..4ffd90f6fb8b0 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts @@ -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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Delete list DS API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +export type DeleteListIndexResponse = z.infer; +export const DeleteListIndexResponse = z.object({ + acknowledged: z.boolean(), +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml new file mode 100644 index 0000000000000..ae43c58726d52 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml @@ -0,0 +1,55 @@ +openapi: 3.0.0 +info: + title: Delete list DS API endpoint + version: '2023-10-31' +paths: + /api/lists/index: + delete: + x-labels: [serverless, ess] + operationId: DeleteListIndex + x-codegen-enabled: true + summary: Delete list data streams + description: Delete the `.lists` and `.items` data streams. + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: [acknowledged] + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List data stream not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.ts similarity index 76% rename from packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.ts index 178641cd8d6af..fe9f7bee0e688 100644 --- a/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml new file mode 100644 index 0000000000000..b95afcdc1ed3b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml @@ -0,0 +1,82 @@ +openapi: 3.0.0 +info: + title: Delete list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + delete: + x-labels: [serverless, ess] + operationId: DeleteListItem + x-codegen-enabled: true + summary: Delete a list item + description: Delete a list item using its `id`, or its `list_id` and `value` fields. + parameters: + - name: id + in: query + required: false + description: Required if `list_id` and `value` are not specified + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: list_id + in: query + required: false + description: Required if `id` is not specified + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: value + in: query + required: false + description: Required if `id` is not specified + schema: + type: string + - name: refresh + in: query + required: false + description: Determines when changes made by the request are made visible to search + schema: + type: string + enum: ['true', 'false', 'wait_for'] + default: 'false' + responses: + 200: + description: Successful response + content: + application/json: + schema: + oneOf: + - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + - type: array + items: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List item not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.gen.ts new file mode 100644 index 0000000000000..87e05bd24e481 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.gen.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Export list items API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { ListId } from '../model/list_common.gen'; + +export type ExportListItemsRequestQuery = z.infer; +export const ExportListItemsRequestQuery = z.object({ + /** + * List's id to export + */ + list_id: ListId, +}); +export type ExportListItemsRequestQueryInput = z.input; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.schema.yaml new file mode 100644 index 0000000000000..999eb4a0ae42d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/export_list_items/export_list_items.schema.yaml @@ -0,0 +1,60 @@ +openapi: 3.0.0 +info: + title: Export list items API endpoint + version: '2023-10-31' +paths: + /api/lists/items/_export: + post: + x-labels: [serverless, ess] + operationId: ExportListItems + x-codegen-enabled: true + summary: Export list items + description: Export list item values from the specified list. + parameters: + - name: list_id + in: query + required: true + description: List's id to export + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + responses: + 200: + description: Successful response + content: + application/ndjson: + schema: + type: string + format: binary + description: A `.txt` file containing list items from the specified list + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.gen.ts similarity index 85% rename from packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.gen.ts index f693965e91e2e..e40c6fe9e2fc1 100644 --- a/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.schema.yaml similarity index 77% rename from packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.schema.yaml index 21cf4ffd61841..746b3e9fdbe37 100644 --- a/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_list_items/find_list_items.schema.yaml @@ -34,7 +34,7 @@ paths: required: false description: Determines which field is used to sort the results schema: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - name: sort_order in: query required: false @@ -94,31 +94,31 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: schemas: FindListItemsCursor: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' FindListItemsFilter: type: string diff --git a/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.gen.ts similarity index 84% rename from packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.gen.ts index ec104f2e6c2b1..74f8ba0217d68 100644 --- a/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.schema.yaml similarity index 76% rename from packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.schema.yaml index 3bb55decacff6..9b0012e8d6968 100644 --- a/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/find_lists/find_lists.schema.yaml @@ -28,7 +28,7 @@ paths: required: false description: Determines which field is used to sort the results schema: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' - name: sort_order in: query required: false @@ -88,31 +88,31 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: schemas: FindListsCursor: - $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' FindListsFilter: type: string diff --git a/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.gen.ts similarity index 77% rename from packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.gen.ts index b71b05bd75955..baf9d9308a93c 100644 --- a/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.schema.yaml similarity index 75% rename from packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.schema.yaml index 520213e949c1d..f3fae45159346 100644 --- a/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/import_list_items/import_list_items.schema.yaml @@ -73,29 +73,29 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 409: description: List with specified list_id does not exist response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/index.ts new file mode 100644 index 0000000000000..6ff15e6109c68 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/index.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +export * from './model/list_common.gen'; +export * from './model/list_schemas.gen'; +export * from './create_list_index/create_list_index.gen'; +export * from './create_list_item/create_list_item.gen'; +export * from './create_list/create_list.gen'; +export * from './delete_list_index/delete_list_index.gen'; +export * from './delete_list_item/delete_list_item.gen'; +export * from './delete_list/delete_list.gen'; +export * from './find_list_items/find_list_items.gen'; +export * from './find_lists/find_lists.gen'; +export * from './export_list_items/export_list_items.gen'; +export * from './import_list_items/import_list_items.gen'; +export * from './patch_list_item/patch_list_item.gen'; +export * from './patch_list/patch_list.gen'; +export * from './read_list_index/read_list_index.gen'; +export * from './read_list_item/read_list_item.gen'; +export * from './read_list/read_list.gen'; +export * from './update_list_item/update_list_item.gen'; +export * from './update_list/update_list.gen'; diff --git a/packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts similarity index 82% rename from packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts index 9a51bd0eeb5ad..536e0b859e45a 100644 --- a/packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml new file mode 100644 index 0000000000000..808e99c7b1e13 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml @@ -0,0 +1,59 @@ +openapi: 3.0.0 +info: + title: Common List Attributes + version: 'not applicable' +paths: {} +components: + schemas: + ListId: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListType: + type: string + enum: + - binary + - boolean + - byte + - date + - date_nanos + - date_range + - double + - double_range + - float + - float_range + - geo_point + - geo_shape + - half_float + - integer + - integer_range + - ip + - ip_range + - keyword + - long + - long_range + - shape + - short + - text + + ListName: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListDescription: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListMetadata: + type: object + additionalProperties: true + + ListItemId: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListItemValue: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListItemDescription: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListItemMetadata: + type: object + additionalProperties: true diff --git a/packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts similarity index 80% rename from packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts index 14d9547c35b59..cd95d20853c11 100644 --- a/packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-lists-common/api/model/list_schemas.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_schemas.schema.yaml similarity index 100% rename from packages/kbn-securitysolution-lists-common/api/model/list_schemas.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/model/list_schemas.schema.yaml diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts new file mode 100644 index 0000000000000..f2a67181d396d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Patch list API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { ListId, ListName, ListDescription, ListMetadata } from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type PatchListRequestBody = z.infer; +export const PatchListRequestBody = z.object({ + id: ListId, + name: ListName.optional(), + description: ListDescription.optional(), + meta: ListMetadata.optional(), + version: z.number().int().min(1).optional(), + _version: z.string().optional(), +}); +export type PatchListRequestBodyInput = z.input; + +export type PatchListResponse = z.infer; +export const PatchListResponse = List; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml new file mode 100644 index 0000000000000..6a61e668ced87 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml @@ -0,0 +1,74 @@ +openapi: 3.0.0 +info: + title: Patch list API endpoint + version: '2023-10-31' +paths: + /api/lists: + patch: + x-labels: [serverless, ess] + operationId: PatchList + x-codegen-enabled: true + summary: Patch a list + description: Update specific fields of an existing list using the list ID. + requestBody: + description: List's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + name: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListName' + description: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListDescription' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListMetadata' + version: + type: integer + minimum: 1 + _version: + type: string + required: + - id + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts new file mode 100644 index 0000000000000..e5c06ddd7c251 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Patch list item API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { ListItemId, ListItemValue, ListItemMetadata } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type PatchListItemRequestBody = z.infer; +export const PatchListItemRequestBody = z.object({ + id: ListItemId, + value: ListItemValue.optional(), + meta: ListItemMetadata.optional(), + _version: z.string().optional(), + /** + * Determines when changes made by the request are made visible to search + */ + refresh: z.enum(['true', 'false', 'wait_for']).optional(), +}); +export type PatchListItemRequestBodyInput = z.input; + +export type PatchListItemResponse = z.infer; +export const PatchListItemResponse = ListItem; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml new file mode 100644 index 0000000000000..fdd7a020d098f --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml @@ -0,0 +1,76 @@ +openapi: 3.0.0 +info: + title: Patch list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + patch: + x-labels: [serverless, ess] + operationId: PatchListItem + x-codegen-enabled: true + summary: Patch a list item + description: Update specific fields of an existing list item using the list item ID. + requestBody: + description: List item's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemId' + value: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemValue' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemMetadata' + _version: + type: string + refresh: + type: string + enum: + - 'true' + - 'false' + - wait_for + description: Determines when changes made by the request are made visible to search + required: + - id + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List item not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts new file mode 100644 index 0000000000000..232f4b00540c5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts @@ -0,0 +1,428 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Lists API client for quickstart + * version: Bundle (no version) + */ + +import type { KbnClient } from '@kbn/test'; +import { ToolingLog } from '@kbn/tooling-log'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { catchAxiosErrorFormatAndThrow } from '@kbn/securitysolution-utils'; + +import type { CreateListIndexResponse } from './create_list_index/create_list_index.gen'; +import type { + CreateListItemRequestBodyInput, + CreateListItemResponse, +} from './create_list_item/create_list_item.gen'; +import type { CreateListRequestBodyInput, CreateListResponse } from './create_list/create_list.gen'; +import type { DeleteListIndexResponse } from './delete_list_index/delete_list_index.gen'; +import type { + DeleteListItemRequestQueryInput, + DeleteListItemResponse, +} from './delete_list_item/delete_list_item.gen'; +import type { + DeleteListRequestQueryInput, + DeleteListResponse, +} from './delete_list/delete_list.gen'; +import type { ExportListItemsRequestQueryInput } from './export_list_items/export_list_items.gen'; +import type { + FindListItemsRequestQueryInput, + FindListItemsResponse, +} from './find_list_items/find_list_items.gen'; +import type { FindListsRequestQueryInput, FindListsResponse } from './find_lists/find_lists.gen'; +import type { + ImportListItemsRequestQueryInput, + ImportListItemsResponse, +} from './import_list_items/import_list_items.gen'; +import type { + PatchListItemRequestBodyInput, + PatchListItemResponse, +} from './patch_list_item/patch_list_item.gen'; +import type { PatchListRequestBodyInput, PatchListResponse } from './patch_list/patch_list.gen'; +import type { ReadListIndexResponse } from './read_list_index/read_list_index.gen'; +import type { + ReadListItemRequestQueryInput, + ReadListItemResponse, +} from './read_list_item/read_list_item.gen'; +import type { ReadListPrivilegesResponse } from './read_list_privileges/read_list_privileges.gen'; +import type { ReadListRequestQueryInput, ReadListResponse } from './read_list/read_list.gen'; +import type { + UpdateListItemRequestBodyInput, + UpdateListItemResponse, +} from './update_list_item/update_list_item.gen'; +import type { UpdateListRequestBodyInput, UpdateListResponse } from './update_list/update_list.gen'; + +export interface ClientOptions { + kbnClient: KbnClient; + log: ToolingLog; +} + +export class Client { + readonly kbnClient: KbnClient; + readonly log: ToolingLog; + + constructor(options: ClientOptions) { + this.kbnClient = options.kbnClient; + this.log = options.log; + } + /** + * Create a new list. + */ + async createList(props: CreateListProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Create `.lists` and `.items` data streams in the relevant space. + */ + async createListIndex() { + this.log.info(`${new Date().toISOString()} Calling API CreateListIndex`); + return this.kbnClient + .request({ + path: '/api/lists/index', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Create a list item and associate it with the specified list. + +All list items in the same list must be the same type. For example, each list item in an `ip` list must define a specific IP address. +> info +> Before creating a list item, you must create a list. + + */ + async createListItem(props: CreateListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API CreateListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Delete a list using the list ID. +> info +> When you delete a list, all of its list items are also deleted. + + */ + async deleteList(props: DeleteListProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Delete the `.lists` and `.items` data streams. + */ + async deleteListIndex() { + this.log.info(`${new Date().toISOString()} Calling API DeleteListIndex`); + return this.kbnClient + .request({ + path: '/api/lists/index', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Delete a list item using its `id`, or its `list_id` and `value` fields. + */ + async deleteListItem(props: DeleteListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API DeleteListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'DELETE', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Export list item values from the specified list. + */ + async exportListItems(props: ExportListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API ExportListItems`); + return this.kbnClient + .request({ + path: '/api/lists/items/_export', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get all list items in the specified list. + */ + async findListItems(props: FindListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API FindListItems`); + return this.kbnClient + .request({ + path: '/api/lists/items/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get a paginated subset of lists. By default, the first page is returned, with 20 results per page. + */ + async findLists(props: FindListsProps) { + this.log.info(`${new Date().toISOString()} Calling API FindLists`); + return this.kbnClient + .request({ + path: '/api/lists/_find', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Import list items from a TXT or CSV file. The maximum file size is 9 million bytes. + +You can import items to a new or existing list. + + */ + async importListItems(props: ImportListItemsProps) { + this.log.info(`${new Date().toISOString()} Calling API ImportListItems`); + return this.kbnClient + .request({ + path: '/api/lists/items/_import', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'POST', + body: props.attachment, + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update specific fields of an existing list using the list ID. + */ + async patchList(props: PatchListProps) { + this.log.info(`${new Date().toISOString()} Calling API PatchList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update specific fields of an existing list item using the list item ID. + */ + async patchListItem(props: PatchListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API PatchListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PATCH', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get the details of a list using the list ID. + */ + async readList(props: ReadListProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Verify that `.lists` and `.items` data streams exist. + */ + async readListIndex() { + this.log.info(`${new Date().toISOString()} Calling API ReadListIndex`); + return this.kbnClient + .request({ + path: '/api/lists/index', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Get the details of a list item. + */ + async readListItem(props: ReadListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API ReadListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + + query: props.query, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + async readListPrivileges() { + this.log.info(`${new Date().toISOString()} Calling API ReadListPrivileges`); + return this.kbnClient + .request({ + path: '/api/lists/privileges', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update a list using the list ID. The original list is replaced, and all unspecified fields are deleted. +> info +> You cannot modify the `id` value. + + */ + async updateList(props: UpdateListProps) { + this.log.info(`${new Date().toISOString()} Calling API UpdateList`); + return this.kbnClient + .request({ + path: '/api/lists', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } + /** + * Update a list item using the list item ID. The original list item is replaced, and all unspecified fields are deleted. +> info +> You cannot modify the `id` value. + + */ + async updateListItem(props: UpdateListItemProps) { + this.log.info(`${new Date().toISOString()} Calling API UpdateListItem`); + return this.kbnClient + .request({ + path: '/api/lists/items', + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', + }, + method: 'PUT', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } +} + +export interface CreateListProps { + body: CreateListRequestBodyInput; +} +export interface CreateListItemProps { + body: CreateListItemRequestBodyInput; +} +export interface DeleteListProps { + query: DeleteListRequestQueryInput; +} +export interface DeleteListItemProps { + query: DeleteListItemRequestQueryInput; +} +export interface ExportListItemsProps { + query: ExportListItemsRequestQueryInput; +} +export interface FindListItemsProps { + query: FindListItemsRequestQueryInput; +} +export interface FindListsProps { + query: FindListsRequestQueryInput; +} +export interface ImportListItemsProps { + query: ImportListItemsRequestQueryInput; + attachment: FormData; +} +export interface PatchListProps { + body: PatchListRequestBodyInput; +} +export interface PatchListItemProps { + body: PatchListItemRequestBodyInput; +} +export interface ReadListProps { + query: ReadListRequestQueryInput; +} +export interface ReadListItemProps { + query: ReadListItemRequestQueryInput; +} +export interface UpdateListProps { + body: UpdateListRequestBodyInput; +} +export interface UpdateListItemProps { + body: UpdateListItemRequestBodyInput; +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts new file mode 100644 index 0000000000000..d2967d71d57e5 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Read list API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { ListId } from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type ReadListRequestQuery = z.infer; +export const ReadListRequestQuery = z.object({ + /** + * List's `id` value + */ + id: ListId, +}); +export type ReadListRequestQueryInput = z.input; + +export type ReadListResponse = z.infer; +export const ReadListResponse = List; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml new file mode 100644 index 0000000000000..280a6fdab7543 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml @@ -0,0 +1,58 @@ +openapi: 3.0.0 +info: + title: Read list API endpoint + version: '2023-10-31' +paths: + /api/lists: + get: + x-labels: [serverless, ess] + operationId: ReadList + x-codegen-enabled: true + summary: Get list details + description: Get the details of a list using the list ID. + parameters: + - name: id + in: query + required: true + description: List's `id` value + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts new file mode 100644 index 0000000000000..bf0aec4dc6bcf --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Read list DS existence status API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +export type ReadListIndexResponse = z.infer; +export const ReadListIndexResponse = z.object({ + list_index: z.boolean(), + list_item_index: z.boolean(), +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml new file mode 100644 index 0000000000000..40dbddf25e69e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml @@ -0,0 +1,57 @@ +openapi: 3.0.0 +info: + title: Read list DS existence status API endpoint + version: '2023-10-31' +paths: + /api/lists/index: + get: + x-labels: [serverless, ess] + operationId: ReadListIndex + x-codegen-enabled: true + summary: Get status of list data streams + description: Verify that `.lists` and `.items` data streams exist. + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + list_index: + type: boolean + list_item_index: + type: boolean + required: [list_index, list_item_index] + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List data stream(s) not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.ts new file mode 100644 index 0000000000000..d22ee46022266 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.ts @@ -0,0 +1,40 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Read list item API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { ListId } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type ReadListItemRequestQuery = z.infer; +export const ReadListItemRequestQuery = z.object({ + /** + * Required if `list_id` and `value` are not specified + */ + id: ListId.optional(), + /** + * Required if `id` is not specified + */ + list_id: ListId.optional(), + /** + * Required if `id` is not specified + */ + value: z.string().optional(), +}); +export type ReadListItemRequestQueryInput = z.input; + +export type ReadListItemResponse = z.infer; +export const ReadListItemResponse = z.union([ListItem, z.array(ListItem)]); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml new file mode 100644 index 0000000000000..a41fb497f611a --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml @@ -0,0 +1,74 @@ +openapi: 3.0.0 +info: + title: Read list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + get: + x-labels: [serverless, ess] + operationId: ReadListItem + x-codegen-enabled: true + summary: Get a list item + description: Get the details of a list item. + parameters: + - name: id + in: query + required: false + description: Required if `list_id` and `value` are not specified + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: list_id + in: query + required: false + description: Required if `id` is not specified + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: value + in: query + required: false + description: Required if `id` is not specified + schema: + type: string + responses: + 200: + description: Successful response + content: + application/json: + schema: + oneOf: + - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + - type: array + items: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List item not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.gen.ts similarity index 76% rename from packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.gen.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.gen.ts index 356915ba03cff..da6e7e95076da 100644 --- a/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.gen.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.gen.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ /* diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.schema.yaml similarity index 78% rename from packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.schema.yaml index ec8604e80694e..df7b4a5f5174b 100644 --- a/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.schema.yaml +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/read_list_privileges/read_list_privileges.schema.yaml @@ -33,26 +33,26 @@ paths: application/json: schema: oneOf: - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 403: description: Not enough privileges response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: schemas: diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts new file mode 100644 index 0000000000000..ffb28c3d0b530 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Update list API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { ListId, ListName, ListDescription, ListMetadata } from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type UpdateListRequestBody = z.infer; +export const UpdateListRequestBody = z.object({ + id: ListId, + name: ListName, + description: ListDescription, + meta: ListMetadata.optional(), + version: z.number().int().min(1).optional(), + _version: z.string().optional(), +}); +export type UpdateListRequestBodyInput = z.input; + +export type UpdateListResponse = z.infer; +export const UpdateListResponse = List; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml new file mode 100644 index 0000000000000..a059ede38584c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml @@ -0,0 +1,79 @@ +openapi: 3.0.0 +info: + title: Update list API endpoint + version: '2023-10-31' +paths: + /api/lists: + put: + x-labels: [serverless, ess] + operationId: UpdateList + x-codegen-enabled: true + summary: Update a list + description: | + Update a list using the list ID. The original list is replaced, and all unspecified fields are deleted. + > info + > You cannot modify the `id` value. + requestBody: + description: List's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + name: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListName' + description: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListDescription' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListMetadata' + version: + type: integer + minimum: 1 + _version: + type: string + required: + - id + - name + - description + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts new file mode 100644 index 0000000000000..f5667676ab4c6 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Update list item API endpoint + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; + +import { ListItemId, ListItemValue, ListItemMetadata } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type UpdateListItemRequestBody = z.infer; +export const UpdateListItemRequestBody = z.object({ + id: ListItemId, + value: ListItemValue, + meta: ListItemMetadata.optional(), + _version: z.string().optional(), +}); +export type UpdateListItemRequestBodyInput = z.input; + +export type UpdateListItemResponse = z.infer; +export const UpdateListItemResponse = ListItem; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml new file mode 100644 index 0000000000000..04d86cf1947a9 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml @@ -0,0 +1,73 @@ +openapi: 3.0.0 +info: + title: Update list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + put: + x-labels: [serverless, ess] + operationId: UpdateListItem + x-codegen-enabled: true + summary: Update a list item + description: | + Update a list item using the list item ID. The original list item is replaced, and all unspecified fields are deleted. + > info + > You cannot modify the `id` value. + requestBody: + description: List item's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemId' + value: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemValue' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemMetadata' + _version: + type: string + required: + - id + - value + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List item not found response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../../../../../packages/kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml similarity index 100% rename from packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml diff --git a/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml similarity index 100% rename from packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml diff --git a/packages/kbn-securitysolution-lists-common/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-lists-common/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/package.json new file mode 100644 index 0000000000000..4e2b035218592 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/package.json @@ -0,0 +1,11 @@ +{ + "description": "Security Solution Lists common package", + "license": "Elastic License 2.0", + "name": "@kbn/securitysolution-lists-common", + "private": true, + "version": "1.0.0", + "scripts": { + "openapi:generate": "node scripts/openapi_generate", + "openapi:bundle": "node scripts/openapi_bundle" + } +} diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js new file mode 100644 index 0000000000000..609ed8bb08078 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +require('../../../../../../src/setup_node_env'); +// eslint-disable-next-line import/no-nodejs-modules +const { join, resolve } = require('path'); +const { bundle } = require('@kbn/openapi-bundler'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/serverless/security_solution_lists_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['serverless'], + prototypeDocument: join(ROOT, 'scripts/openapi_bundle_info/lists_serverless.info.yaml'), + }, + }); + + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/ess/security_solution_lists_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['ess'], + prototypeDocument: join(ROOT, 'scripts/openapi_bundle_info/lists_ess.info.yaml'), + }, + }); +})(); diff --git a/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle_info/lists_ess.info.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle_info/lists_ess.info.yaml similarity index 100% rename from packages/kbn-securitysolution-lists-common/scripts/openapi_bundle_info/lists_ess.info.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle_info/lists_ess.info.yaml diff --git a/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle_info/lists_serverless.info.yaml b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle_info/lists_serverless.info.yaml similarity index 100% rename from packages/kbn-securitysolution-lists-common/scripts/openapi_bundle_info/lists_serverless.info.yaml rename to x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle_info/lists_serverless.info.yaml diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js new file mode 100644 index 0000000000000..ecda1a791e1fc --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js @@ -0,0 +1,51 @@ +/* + * 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. + */ + +require('../../../../../../src/setup_node_env'); +// eslint-disable-next-line import/no-nodejs-modules +const { join, resolve } = require('path'); +const { generate } = require('@kbn/openapi-generator'); +const { REPO_ROOT } = require('@kbn/repo-info'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await generate({ + title: 'OpenAPI Lists API Schemas', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'zod_operation_schema', + }); + + await generate({ + title: 'Lists API client for tests', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'api_client_supertest', + skipLinting: true, + bundle: { + outFile: join( + REPO_ROOT, + 'x-pack/test/api_integration/services/security_solution_lists_api.gen.ts' + ), + }, + }); + + await generate({ + title: 'Lists API client for quickstart', + rootDir: ROOT, + sourceGlob: './api/**/*.schema.yaml', + templateName: 'api_client_quickstart', + skipLinting: true, + bundle: { + outFile: join( + REPO_ROOT, + 'x-pack/solutions/security/packages/kbn-securitysolution-lists-common/api/quickstart_client.gen.ts' + ), + }, + }); +})(); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/tsconfig.json new file mode 100644 index 0000000000000..6a6637ff64a2c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-lists-common/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "exclude": ["target/**/*"], + "extends": "../../../../../tsconfig.base.json", + "include": ["**/*.ts"], + "kbn_references": [ + "@kbn/zod-helpers", + "@kbn/openapi-common", + "@kbn/test", + "@kbn/tooling-log", + "@kbn/core-http-common", + "@kbn/securitysolution-utils", + "@kbn/zod", + ] +} diff --git a/packages/kbn-securitysolution-t-grid/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/README.md similarity index 100% rename from packages/kbn-securitysolution-t-grid/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-t-grid/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/index.ts new file mode 100644 index 0000000000000..371d48e06c148 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './src/constants'; +export * from './src/utils'; +// eslint-disable-next-line @kbn/imports/no_boundary_crossing +export * from './src/mock'; diff --git a/packages/kbn-securitysolution-t-grid/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-t-grid/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-t-grid/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/package.json new file mode 100644 index 0000000000000..d2f04084da369 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/securitysolution-t-grid", + "version": "1.0.0", + "description": "security solution t-grid packages will allow sharing components between timelines and security_solution plugin until we transfer all functionality to timelines plugin", + "license": "Elastic License 2.0", + "private": true +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/constants/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/constants/index.ts new file mode 100644 index 0000000000000..a57893d639955 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/constants/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const HIGHLIGHTED_DROP_TARGET_CLASS_NAME = 'highlighted-drop-target'; +export const EMPTY_PROVIDERS_GROUP_CLASS_NAME = 'empty-providers-group'; + +/** The draggable will move this many pixels via the keyboard when the arrow key is pressed */ +export const KEYBOARD_DRAG_OFFSET = 20; + +export const DRAGGABLE_KEYBOARD_WRAPPER_CLASS_NAME = 'draggable-keyboard-wrapper'; + +export const ROW_RENDERER_CLASS_NAME = 'row-renderer'; + +export const NOTES_CONTAINER_CLASS_NAME = 'notes-container'; + +export const NOTE_CONTENT_CLASS_NAME = 'note-content'; + +/** This class is added to the document body while dragging */ +export const IS_DRAGGING_CLASS_NAME = 'is-dragging'; + +export const HOVER_ACTIONS_ALWAYS_SHOW_CLASS_NAME = 'hover-actions-always-show'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/mock/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/mock/index.ts new file mode 100644 index 0000000000000..770bf1ffb0189 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/mock/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './mock_event_details'; diff --git a/packages/kbn-securitysolution-t-grid/src/mock/mock_event_details.ts b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/mock/mock_event_details.ts similarity index 97% rename from packages/kbn-securitysolution-t-grid/src/mock/mock_event_details.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/mock/mock_event_details.ts index 5152132cda4bb..538f6fa2cadc0 100644 --- a/packages/kbn-securitysolution-t-grid/src/mock/mock_event_details.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/mock/mock_event_details.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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. */ export const eventHit = { diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/utils/api/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/utils/api/index.ts new file mode 100644 index 0000000000000..add7df10fe13e --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/utils/api/index.ts @@ -0,0 +1,41 @@ +/* + * 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 { has } from 'lodash/fp'; + +export interface AppError extends Error { + body: { + message: string; + }; +} + +export interface KibanaError extends AppError { + body: { + message: string; + statusCode: number; + }; +} + +export interface SecurityAppError extends AppError { + body: { + message: string; + status_code: number; + }; +} + +export const isKibanaError = (error: unknown): error is KibanaError => + has('message', error) && has('body.message', error) && has('body.statusCode', error); + +export const isSecurityAppError = (error: unknown): error is SecurityAppError => + has('message', error) && has('body.message', error) && has('body.status_code', error); + +export const isAppError = (error: unknown): error is AppError => + isKibanaError(error) || isSecurityAppError(error); + +export const isNotFoundError = (error: unknown) => + (isKibanaError(error) && error.body.statusCode === 404) || + (isSecurityAppError(error) && error.body.status_code === 404); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/utils/drag_and_drop/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/utils/drag_and_drop/index.ts new file mode 100644 index 0000000000000..d954ebb055f1d --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/utils/drag_and_drop/index.ts @@ -0,0 +1,132 @@ +/* + * 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 type { DropResult } from '@hello-pangea/dnd'; + +export const draggableIdPrefix = 'draggableId'; + +export const droppableIdPrefix = 'droppableId'; + +export const draggableContentPrefix = `${draggableIdPrefix}.content.`; + +export const draggableTimelineProvidersPrefix = `${draggableIdPrefix}.timelineProviders.`; + +export const draggableFieldPrefix = `${draggableIdPrefix}.field.`; + +export const droppableContentPrefix = `${droppableIdPrefix}.content.`; + +export const droppableFieldPrefix = `${droppableIdPrefix}.field.`; + +export const droppableTimelineProvidersPrefix = `${droppableIdPrefix}.timelineProviders.`; + +export const droppableTimelineColumnsPrefix = `${droppableIdPrefix}.timelineColumns.`; + +export const droppableTimelineFlyoutBottomBarPrefix = `${droppableIdPrefix}.flyoutButton.`; + +export const getDraggableId = (dataProviderId: string): string => + `${draggableContentPrefix}${dataProviderId}`; + +export const getDraggableFieldId = ({ + contextId, + fieldId, +}: { + contextId: string; + fieldId: string; +}): string => `${draggableFieldPrefix}${escapeContextId(contextId)}.${escapeFieldId(fieldId)}`; + +export const getTimelineProviderDroppableId = ({ + groupIndex, + timelineId, +}: { + groupIndex: number; + timelineId: string; +}): string => `${droppableTimelineProvidersPrefix}${timelineId}.group.${groupIndex}`; + +export const getTimelineProviderDraggableId = ({ + dataProviderId, + groupIndex, + timelineId, +}: { + dataProviderId: string; + groupIndex: number; + timelineId: string; +}): string => + `${draggableTimelineProvidersPrefix}${timelineId}.group.${groupIndex}.${dataProviderId}`; + +export const getDroppableId = (visualizationPlaceholderId: string): string => + `${droppableContentPrefix}${visualizationPlaceholderId}`; + +export const sourceIsContent = (result: DropResult): boolean => + result.source.droppableId.startsWith(droppableContentPrefix); + +export const sourceAndDestinationAreSameTimelineProviders = (result: DropResult): boolean => { + const regex = /^droppableId\.timelineProviders\.(\S+)\./; + const sourceMatches = result.source.droppableId.match(regex) || []; + const destinationMatches = + (result.destination && result.destination.droppableId.match(regex)) || []; + + return ( + sourceMatches.length >= 2 && + destinationMatches.length >= 2 && + sourceMatches[1] === destinationMatches[1] + ); +}; + +export const draggableIsContent = (result: DropResult | { draggableId: string }): boolean => + result.draggableId.startsWith(draggableContentPrefix); + +export const draggableIsField = (result: DropResult | { draggableId: string }): boolean => + result.draggableId.startsWith(draggableFieldPrefix); + +export const reasonIsDrop = (result: DropResult): boolean => result.reason === 'DROP'; + +export const destinationIsTimelineProviders = (result: DropResult): boolean => + result.destination != null && + result.destination.droppableId.startsWith(droppableTimelineProvidersPrefix); + +export const destinationIsTimelineColumns = (result: DropResult): boolean => + result.destination != null && + result.destination.droppableId.startsWith(droppableTimelineColumnsPrefix); + +export const destinationIsTimelineButton = (result: DropResult): boolean => + result.destination != null && + result.destination.droppableId.startsWith(droppableTimelineFlyoutBottomBarPrefix); + +export const getProviderIdFromDraggable = (result: DropResult): string => + result.draggableId.substring(result.draggableId.lastIndexOf('.') + 1); + +export const getFieldIdFromDraggable = (result: DropResult): string => + unEscapeFieldId(result.draggableId.substring(result.draggableId.lastIndexOf('.') + 1)); + +export const escapeDataProviderId = (path: string) => path.replace(/\./g, '_'); + +export const escapeContextId = (path: string) => path.replace(/\./g, '_'); + +export const escapeFieldId = (path: string) => path.replace(/\./g, '!!!DOT!!!'); + +export const unEscapeFieldId = (path: string) => path.replace(/!!!DOT!!!/g, '.'); + +export const providerWasDroppedOnTimeline = (result: DropResult): boolean => + reasonIsDrop(result) && + draggableIsContent(result) && + sourceIsContent(result) && + destinationIsTimelineProviders(result); + +export const userIsReArrangingProviders = (result: DropResult): boolean => + reasonIsDrop(result) && sourceAndDestinationAreSameTimelineProviders(result); + +export const fieldWasDroppedOnTimelineColumns = (result: DropResult): boolean => + reasonIsDrop(result) && draggableIsField(result) && destinationIsTimelineColumns(result); + +/** + * Prevents fields from being dragged or dropped to any area other than column + * header drop zone in the timeline + */ +export const DRAG_TYPE_FIELD = 'drag-type-field'; + +/** This class is added to the document body while timeline field dragging */ +export const IS_TIMELINE_FIELD_DRAGGING_CLASS_NAME = 'is-timeline-field-dragging'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/utils/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/utils/index.ts new file mode 100644 index 0000000000000..cafe8ec570c86 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/src/utils/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export * from './api'; +export * from './drag_and_drop'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/tsconfig.json new file mode 100644 index 0000000000000..131ff3e6bb433 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-t-grid/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-securitysolution-utils/README.md b/x-pack/solutions/security/packages/kbn-securitysolution-utils/README.md similarity index 100% rename from packages/kbn-securitysolution-utils/README.md rename to x-pack/solutions/security/packages/kbn-securitysolution-utils/README.md diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/index.ts new file mode 100644 index 0000000000000..dcf5ee7c47791 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './src/add_remove_id_to_item'; +export * from './src/axios'; +export * from './src/transform_data_to_ndjson'; +export * from './src/path_validations'; +export * from './src/esql'; +export * from './src/debounce_async/debounce_async'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/jest.config.js b/x-pack/solutions/security/packages/kbn-securitysolution-utils/jest.config.js new file mode 100644 index 0000000000000..c25893390c684 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/jest.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/solutions/security/packages/kbn-securitysolution-utils'], +}; diff --git a/packages/kbn-securitysolution-utils/kibana.jsonc b/x-pack/solutions/security/packages/kbn-securitysolution-utils/kibana.jsonc similarity index 100% rename from packages/kbn-securitysolution-utils/kibana.jsonc rename to x-pack/solutions/security/packages/kbn-securitysolution-utils/kibana.jsonc diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/package.json b/x-pack/solutions/security/packages/kbn-securitysolution-utils/package.json new file mode 100644 index 0000000000000..d9311ef37a28b --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/securitysolution-utils", + "version": "1.0.0", + "description": "security solution utilities to use across plugins such lists, security_solution, cases, etc...", + "license": "Elastic License 2.0", + "private": true, + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.test.ts new file mode 100644 index 0000000000000..13d13b2acf89c --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.test.ts @@ -0,0 +1,77 @@ +/* + * 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 { addIdToItem, removeIdFromItem } from '.'; + +jest.mock('uuid', () => ({ + v4: jest.fn().mockReturnValue('123'), +})); + +describe('add_remove_id_to_item', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('addIdToItem', () => { + test('it adds an id to an empty item', () => { + expect(addIdToItem({})).toEqual({ id: '123' }); + }); + + test('it adds a complex object', () => { + expect( + addIdToItem({ + field: '', + type: 'mapping', + value: '', + }) + ).toEqual({ + id: '123', + field: '', + type: 'mapping', + value: '', + }); + }); + + test('it adds an id to an existing item', () => { + expect(addIdToItem({ test: '456' })).toEqual({ id: '123', test: '456' }); + }); + + test('it does not change the id if it already exists', () => { + expect(addIdToItem({ id: '456' })).toEqual({ id: '456' }); + }); + + test('it returns the same reference if it has an id already', () => { + const obj = { id: '456' }; + expect(addIdToItem(obj)).toBe(obj); + }); + + test('it returns a new reference if it adds an id to an item', () => { + const obj = { test: '456' }; + expect(addIdToItem(obj)).not.toBe(obj); + }); + }); + + describe('removeIdFromItem', () => { + test('it removes an id from an item', () => { + expect(removeIdFromItem({ id: '456' })).toEqual({}); + }); + + test('it returns a new reference if it removes an id from an item', () => { + const obj = { id: '123', test: '456' }; + expect(removeIdFromItem(obj)).not.toBe(obj); + }); + + test('it does not effect an item without an id', () => { + expect(removeIdFromItem({ test: '456' })).toEqual({ test: '456' }); + }); + + test('it returns the same reference if it does not have an id already', () => { + const obj = { test: '456' }; + expect(removeIdFromItem(obj)).toBe(obj); + }); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.ts new file mode 100644 index 0000000000000..5133a13bdbecf --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/add_remove_id_to_item/index.ts @@ -0,0 +1,50 @@ +/* + * 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 { v4 as uuidv4 } from 'uuid'; + +/** + * This is useful for when you have arrays without an ID and need to add one for + * ReactJS keys. I break the types slightly by introducing an id to an arbitrary item + * but then cast it back to the regular type T. + * Usage of this could be considered tech debt as I am adding an ID when the backend + * could be doing the same thing but it depends on how you want to model your data and + * if you view modeling your data with id's to please ReactJS a good or bad thing. + * @param item The item to add an id to. + */ +type NotArray = T extends unknown[] ? never : T; +export const addIdToItem = (item: NotArray): T => { + const maybeId = item as typeof item & { id?: string }; + if (maybeId.id != null) { + return item; + } else { + return { ...item, id: uuidv4() }; + } +}; + +/** + * This is to reverse the id you added to your arrays for ReactJS keys. + * @param item The item to remove the id from. + */ +export const removeIdFromItem = ( + item: NotArray +): + | T + | Pick< + T & { + id?: string | undefined; + }, + Exclude + > => { + const maybeId = item as typeof item & { id?: string }; + if (maybeId.id != null) { + const { id, ...noId } = maybeId; + return noId; + } else { + return item; + } +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/axios/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/axios/index.ts new file mode 100644 index 0000000000000..44972dba93565 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/axios/index.ts @@ -0,0 +1,71 @@ +/* + * 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 { AxiosError } from 'axios'; + +export class FormattedAxiosError extends Error { + public readonly request: { + method: string; + url: string; + data: unknown; + }; + public readonly response: { + status: number; + statusText: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data: any; + }; + + constructor(axiosError: AxiosError) { + const method = axiosError.config?.method ?? ''; + const url = axiosError.config?.url ?? ''; + + super( + `${axiosError.message}${ + axiosError?.response?.data ? `: ${JSON.stringify(axiosError?.response?.data)}` : '' + }${url ? `\n(Request: ${method} ${url})` : ''}` + ); + + this.request = { + method, + url, + data: axiosError.config?.data ?? '', + }; + + this.response = { + status: axiosError?.response?.status ?? 0, + statusText: axiosError?.response?.statusText ?? '', + data: axiosError?.response?.data, + }; + + this.name = this.constructor.name; + } + + toJSON() { + return { + message: this.message, + request: this.request, + response: this.response, + }; + } + + toString() { + return JSON.stringify(this.toJSON(), null, 2); + } +} + +/** + * Used with `promise.catch()`, it will format the Axios error to a new error and will re-throw + * @param error + */ +export const catchAxiosErrorFormatAndThrow = (error: Error): never => { + if (error instanceof AxiosError) { + throw new FormattedAxiosError(error); + } + + throw error; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/client_concurrency/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/client_concurrency/index.ts new file mode 100644 index 0000000000000..3a44e5061d095 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/client_concurrency/index.ts @@ -0,0 +1,35 @@ +/* + * 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 limit from 'p-limit'; + +/** + * This type is just an async function's type + */ +type RequestFactory = () => Promise; + +/** + * Helper function to call a large number of async functions with limited concurrency. + * Example pattern of how to create functions to pass in: + * + * const ruleCopies = duplicateRuleParams(basicRule, 200); + * const functions = ruleCopies.map((rule) => () => detectionsClient.createRule({ body: rule })); + * + * Note that the `map` call in the example returns a *function* that calls detectionsClient.createRule, it doesn't call createRule immediately. + * + * @param functions Async functions to call with limited concurrency + * @param concurrency Maximum number of concurrent function calls + * @returns Results from all functions passed in + */ +export const concurrentlyExec = async ( + requestFactories: Array>, + concurrency: number = 10 +) => { + const limiter = limit(concurrency); + const promises = requestFactories.map((f) => limiter(f)); + return Promise.all(promises); +}; diff --git a/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.test.ts similarity index 77% rename from packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.test.ts index d7e1201e44e8d..7508e99a891fa 100644 --- a/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { debounceAsync } from './debounce_async'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.ts new file mode 100644 index 0000000000000..ac9f2348d0be8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.ts @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/** + * Unlike lodash's debounce, which resolves intermediate calls with the most + * recent value, this implementation waits to resolve intermediate calls until + * the next invocation resolves. + * + * @param fn an async function + * + * @returns A debounced async function that resolves on the next invocation + */ +export function debounceAsync( + fn: (...args: Args) => Result, + intervalMs: number +): (...args: Args) => Promise> { + let timeoutId: ReturnType | undefined; + let resolve: (value: Awaited) => void; + let promise = new Promise>((_resolve) => { + resolve = _resolve; + }); + + return (...args) => { + if (timeoutId) { + clearTimeout(timeoutId); + } + + timeoutId = setTimeout(async () => { + resolve(await fn(...args)); + promise = new Promise((_resolve) => { + resolve = _resolve; + }); + }, intervalMs); + + return promise; + }; +} diff --git a/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.test.ts similarity index 84% rename from packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.test.ts index cb92d34b33ec7..41268ac0fa851 100644 --- a/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { computeIsESQLQueryAggregating } from './compute_if_esql_query_aggregating'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts new file mode 100644 index 0000000000000..d38abdaa481a8 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts @@ -0,0 +1,21 @@ +/* + * 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 { type ESQLAstQueryExpression, parse } from '@kbn/esql-ast'; + +export const isAggregatingQuery = (astExpression: ESQLAstQueryExpression): boolean => + astExpression.commands.some((command) => command.name === 'stats'); + +/** + * compute if esqlQuery is aggregating/grouping, i.e. using STATS...BY command + * @param esqlQuery + * @returns boolean + */ +export const computeIsESQLQueryAggregating = (esqlQuery: string): boolean => { + const { root } = parse(esqlQuery); + return isAggregatingQuery(root); +}; diff --git a/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.test.ts similarity index 80% rename from packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.test.ts index 7a7726c47e143..39dc934dcdd2d 100644 --- a/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.ts new file mode 100644 index 0000000000000..654f09cd0b846 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/get_index_list_from_esql_query.ts @@ -0,0 +1,32 @@ +/* + * 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 { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; + +/** + * parses ES|QL query and returns array of indices + */ +export const getIndexListFromEsqlQuery = (query: string | undefined): string[] => { + try { + const indexString = getIndexPatternFromESQLQuery(query); + + return getIndexListFromIndexString(indexString); + } catch (e) { + return []; + } +}; + +/** + * transforms sting of indices, separated by commas to array + * index*, index2* => [index*, index2*] + */ +export const getIndexListFromIndexString = (indexString: string | undefined): string[] => { + if (!indexString) { + return []; + } + return indexString.split(',').map((index) => index.trim()); +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/index.ts new file mode 100644 index 0000000000000..ff6f8a4552446 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/index.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export * from './compute_if_esql_query_aggregating'; +export * from './get_index_list_from_esql_query'; +export * from './parse_esql_query'; diff --git a/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.test.ts similarity index 90% rename from packages/kbn-securitysolution-utils/src/esql/parse_esql_query.test.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.test.ts index 6c4fdafd8e70b..1e7484fd6e4b5 100644 --- a/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.test.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.test.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { parseEsqlQuery } from './parse_esql_query'; diff --git a/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.ts similarity index 83% rename from packages/kbn-securitysolution-utils/src/esql/parse_esql_query.ts rename to x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.ts index 2a62aed8873a0..6e088bf386fbb 100644 --- a/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.ts +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/esql/parse_esql_query.ts @@ -1,10 +1,8 @@ /* * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". + * 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 { type ESQLAstQueryExpression, parse, ESQLCommandOption, EditorError } from '@kbn/esql-ast'; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts new file mode 100644 index 0000000000000..5304c3a710613 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts @@ -0,0 +1,758 @@ +/* + * 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 { + isPathValid, + hasSimpleExecutableName, + OperatingSystem, + ConditionEntryField, + validateWildcardInput, + validateHasWildcardWithWrongOperator, + validatePotentialWildcardInput, + validateFilePathInput, + WILDCARD_WARNING, + FILEPATH_WARNING, +} from '.'; + +describe('validatePotentialWildcardInput', () => { + it('warns on wildcard when field is file.path.text', () => { + expect( + validatePotentialWildcardInput({ + field: 'file.path.text', + os: OperatingSystem.WINDOWS, + value: 'c:\\path*.exe', + }) + ).toEqual(WILDCARD_WARNING); + }); + it('warns on wildcard when field is not file.path.text', () => { + expect( + validatePotentialWildcardInput({ + field: 'event.category', + os: OperatingSystem.WINDOWS, + value: 'some*value', + }) + ).toEqual(WILDCARD_WARNING); + }); +}); + +describe('validateWildcardInput', () => { + it('warns on wildcard for fields that are not file paths', () => { + expect(validateWildcardInput('*')).toEqual(WILDCARD_WARNING); + }); + it('does not warn if no wildcard', () => { + expect(validateWildcardInput('non-wildcard')).toEqual(undefined); + }); +}); + +describe('validateFilePathInput', () => { + describe('windows', () => { + const os = OperatingSystem.WINDOWS; + + it('does not warn on valid filenames', () => { + expect( + validateFilePathInput({ + os, + value: 'C:\\Windows\\*\\FILENAME.EXE-1231205124.gz', + }) + ).not.toBeDefined(); + expect( + validateFilePathInput({ + os, + value: "C:\\Windows\\*\\test$ as2@13---12!@#A,DS.#$^&$!#~ 'as'd.华语.txt", + }) + ).toEqual(undefined); + }); + + it('warns on wildcard in file name at the end of the path', () => { + expect(validateFilePathInput({ os, value: 'c:\\path*.exe' })).toEqual(WILDCARD_WARNING); + expect( + validateFilePathInput({ + os, + value: 'C:\\Windows\\*\\FILENAME.EXE-*.gz', + }) + ).toEqual(WILDCARD_WARNING); + }); + + it('warns on unix paths or non-windows paths', () => { + expect(validateFilePathInput({ os, value: '/opt/bin' })).toEqual(FILEPATH_WARNING); + }); + + it('warns on malformed paths', () => { + expect(validateFilePathInput({ os, value: 'c:\\path/opt' })).toEqual(FILEPATH_WARNING); + expect(validateFilePathInput({ os, value: '1242' })).toEqual(FILEPATH_WARNING); + expect(validateFilePathInput({ os, value: 'w12efdfa' })).toEqual(FILEPATH_WARNING); + expect(validateFilePathInput({ os, value: 'c:\\folder\\' })).toEqual(FILEPATH_WARNING); + }); + }); + describe('unix paths', () => { + const os = + parseInt((Math.random() * 2).toString(), 10) === 1 + ? OperatingSystem.MAC + : OperatingSystem.LINUX; + + it('does not warn on valid filenames', () => { + expect( + validateFilePathInput({ + os, + value: '/opt/*/FILENAME.EXE-1231205124.gz', + }) + ).not.toEqual(WILDCARD_WARNING); + expect( + validateFilePathInput({ + os, + value: "/opt/*/test$ as2@13---12!@#A,DS.#$^&$!#~ 'as'd.华语.txt", + }) + ).not.toEqual(WILDCARD_WARNING); + }); + it('warns on wildcard in file name at the end of the path', () => { + expect(validateFilePathInput({ os, value: '/opt/bin*' })).toEqual(WILDCARD_WARNING); + expect(validateFilePathInput({ os, value: '/opt/FILENAME.EXE-*.gz' })).toEqual( + WILDCARD_WARNING + ); + }); + + it('warns on windows paths', () => { + expect(validateFilePathInput({ os, value: 'd:\\path\\file.exe' })).toEqual(FILEPATH_WARNING); + }); + + it('warns on malformed paths', () => { + expect(validateFilePathInput({ os, value: 'opt/bin\\file.exe' })).toEqual(FILEPATH_WARNING); + expect(validateFilePathInput({ os, value: '1242' })).toEqual(FILEPATH_WARNING); + expect(validateFilePathInput({ os, value: 'w12efdfa' })).toEqual(FILEPATH_WARNING); + expect(validateFilePathInput({ os, value: '/folder/' })).toEqual(FILEPATH_WARNING); + }); + }); +}); + +describe('Wildcard and invalid operator', () => { + it('should return TRUE when operator is not "WILDCARD" and value contains a wildcard', () => { + expect(validateHasWildcardWithWrongOperator({ operator: 'match', value: 'asdf*' })).toEqual( + true + ); + }); + it('should return FALSE when operator is not "WILDCARD" and value does not contain a wildcard', () => { + expect(validateHasWildcardWithWrongOperator({ operator: 'match', value: 'asdf' })).toEqual( + false + ); + }); + it('should return FALSE when operator is "WILDCARD" and value contains a wildcard', () => { + expect(validateHasWildcardWithWrongOperator({ operator: 'wildcard', value: 'asdf*' })).toEqual( + false + ); + }); + it('should return FALSE when operator is "WILDCARD" and value does not contain a wildcard', () => { + expect(validateHasWildcardWithWrongOperator({ operator: 'wildcard', value: 'asdf' })).toEqual( + false + ); + }); +}); + +describe('No Warnings', () => { + it('should not show warnings on non path entries ', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.HASH, + type: 'match', + value: '5d5b09f6dcb2d53a5fffc60c4ac0d55fabdf556069d6631545f42aa6e3500f2e', + }) + ).toEqual(true); + + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.SIGNER, + type: 'match', + value: '', + }) + ).toEqual(true); + }); +}); + +describe('Unacceptable Windows wildcard paths', () => { + it('should not accept paths that do not have a folder name with a wildcard ', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'c:\\folder', + }) + ).toEqual(false); + }); + + it('should not accept paths that do not have a file name with a wildcard ', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'c:\\path.exe', + }) + ).toEqual(false); + }); + + it('should not accept nested paths that do not have a wildcard', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'c:\\folder\\path.exe', + }) + ).toEqual(false); + }); + + it('should not accept paths with * wildcard and /', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'c:/**/path.exe', + }) + ).toEqual(false); + }); + + it('should not accept paths with ? wildcard and /', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'C:/?indows/pat?', + }) + ).toEqual(false); + }); +}); + +describe('Acceptable Windows wildcard paths', () => { + it('should accept wildcards for folders', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'c:\\**\\path.exe', + }) + ).toEqual(true); + }); + + it('should accept wildcards for folders and files', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'e:\\**\\*.exe', + }) + ).toEqual(true); + }); + + it('should accept paths with single wildcard', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'f:\\*', + }) + ).toEqual(true); + + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'f:\\?', + }) + ).toEqual(true); + }); + + it('should accept paths that have wildcard in filenames', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'a:\\*.*', + }) + ).toEqual(true); + }); + + it('should accept paths with ? as wildcard', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'C:\\?indows\\pat?', + }) + ).toEqual(true); + }); + + it('should accept paths with both ? and * as wildcards', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'C:\\*?', + }) + ).toEqual(true); + }); + + it('should accept paths with multiple wildcards', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'C:\\**', + }) + ).toEqual(true); + + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'C:\\??', + }) + ).toEqual(true); + }); +}); + +describe('Acceptable Windows exact paths', () => { + it('should accept paths when it ends with a folder name', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'match', + value: 'c:\\folder', + }) + ).toEqual(true); + }); + + it('should accept paths when it ends with a file name', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'match', + value: 'c:\\path.exe', + }) + ).toEqual(true); + }); + + it('should accept paths when it ends with a filename in a folder', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'match', + value: 'c:\\folder\\path.exe', + }) + ).toEqual(true); + }); +}); + +describe('Acceptable Windows exact paths with hyphens', () => { + it('should accept paths when paths have folder names with hyphens', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'match', + value: 'c:\\hype-folder-name', + }) + ).toEqual(true); + }); + + it('should accept paths when file names have hyphens', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'match', + value: 'c:\\file-name.exe', + }) + ).toEqual(true); + }); +}); + +describe('Unacceptable Windows exact paths', () => { + it('should not accept paths with /', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'match', + value: 'c:/folder/path.exe', + }) + ).toEqual(false); + }); + + it('should not accept paths not having a in the suffix', () => { + expect( + isPathValid({ + os: OperatingSystem.WINDOWS, + field: ConditionEntryField.PATH, + type: 'match', + value: '\\folder\\path.exe', + }) + ).toEqual(false); + }); +}); + +/// +describe('Unacceptable Mac/Linux wildcard paths', () => { + it('should not accept paths that do not have a folder name with a wildcard ', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/folder', + }) + ).toEqual(false); + }); + + it('should not accept paths that do not have a file name with a wildcard ', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/zip.zip', + }) + ).toEqual(false); + }); + + it('should not accept nested paths that do not have a wildcard', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/opt/pack.tar', + }) + ).toEqual(false); + }); + + it('should not accept paths with * wildcard and \\', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'c:\\**\\path.exe', + }) + ).toEqual(false); + }); + + it('should not accept paths with ? wildcard and \\', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: 'C:\\?indows\\pat?', + }) + ).toEqual(false); + }); +}); + +describe('Acceptable Mac/Linux wildcard paths', () => { + it('should accept wildcards for folders', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/**/file.', + }) + ).toEqual(true); + }); + + it('should accept wildcards for folders and files', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/usr/bi?/*.js', + }) + ).toEqual(true); + }); + + it('should accept paths with single wildcard', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/op*', + }) + ).toEqual(true); + + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/op?', + }) + ).toEqual(true); + }); + + it('should accept paths that have wildcard in filenames', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/*.*', + }) + ).toEqual(true); + }); + + it('should accept paths with ? as wildcard', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/usr/?inux/pat?', + }) + ).toEqual(true); + }); + + it('should accept paths with both ? and * as wildcards', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/usr/*?', + }) + ).toEqual(true); + }); + + it('should accept paths with multiple wildcards', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/usr/**', + }) + ).toEqual(true); + + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'wildcard', + value: '/opt/??', + }) + ).toEqual(true); + }); +}); + +describe('Acceptable Mac/Linux exact paths', () => { + it('should accept paths when it is the root path', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'match', + value: '/', + }) + ).toEqual(true); + }); + + it('should accept paths when it ends with a file name', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'match', + value: '/usr/file.ts', + }) + ).toEqual(true); + }); + + it('should accept paths when it ends with a filename in a folder', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'match', + value: '/opt/z.dmg', + }) + ).toEqual(true); + }); +}); + +describe('Acceptable Mac/Linux exact paths with hyphens', () => { + it('should accept paths when paths have folder names with hyphens', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'match', + value: '/hype-folder-name', + }) + ).toEqual(true); + }); + + it('should accept paths when file names have hyphens', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'match', + value: '/file-name.dmg', + }) + ).toEqual(true); + }); +}); + +describe('Unacceptable Mac/Linux exact paths', () => { + it('should not accept paths with \\', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'match', + value: 'c:\\folder\\path.exe', + }) + ).toEqual(false); + }); + + it('should not accept paths not starting with /', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'match', + value: 'opt/bin', + }) + ).toEqual(false); + }); + + it('should not accept paths ending with /', () => { + expect( + isPathValid({ + os: OperatingSystem.MAC, + field: ConditionEntryField.PATH, + type: 'match', + value: '/opt/bin/', + }) + ).toEqual(false); + }); + + it('should not accept file extensions with hyphens', () => { + expect( + isPathValid({ + os: OperatingSystem.LINUX, + field: ConditionEntryField.PATH, + type: 'match', + value: '/opt/bin/file.d-mg', + }) + ).toEqual(false); + }); +}); + +describe('hasSimpleExecutableName', () => { + it('should return TRUE when MAC/LINUX wildcard paths have an executable name', () => { + const os = + parseInt((Math.random() * 2).toString(), 10) === 1 + ? OperatingSystem.MAC + : OperatingSystem.LINUX; + + expect( + hasSimpleExecutableName({ + os, + type: 'wildcard', + value: '/opt/*/app', + }) + ).toEqual(true); + expect( + hasSimpleExecutableName({ + os, + type: 'wildcard', + value: '/op*/**/app.dmg', + }) + ).toEqual(true); + expect( + hasSimpleExecutableName({ + os, + type: 'wildcard', + value: "/sy*/test$ as2@13---12!@#A,DS.#$^&$!#~ 'as'd.华语.txt", + }) + ).toEqual(true); + }); + + it('should return FALSE when MAC/LINUX wildcard paths have a wildcard in executable name', () => { + const os = + parseInt((Math.random() * 2).toString(), 10) === 1 + ? OperatingSystem.MAC + : OperatingSystem.LINUX; + + expect( + hasSimpleExecutableName({ + os, + type: 'wildcard', + value: '/op/*/*pp', + }) + ).toEqual(false); + expect( + hasSimpleExecutableName({ + os, + type: 'wildcard', + value: '/op*/b**/ap.m**', + }) + ).toEqual(false); + }); + + it('should return TRUE when WINDOWS wildcards paths have a executable name', () => { + expect( + hasSimpleExecutableName({ + os: OperatingSystem.WINDOWS, + type: 'wildcard', + value: 'c:\\**\\path.exe', + }) + ).toEqual(true); + expect( + hasSimpleExecutableName({ + os: OperatingSystem.WINDOWS, + type: 'wildcard', + value: 'C:\\*\\file-name.path华语 1234.txt', + }) + ).toEqual(true); + expect( + hasSimpleExecutableName({ + os: OperatingSystem.WINDOWS, + type: 'wildcard', + value: "C:\\*\\test$ as2@13---12!@#A,DS.#$^&$!#~ 'as'd.华语.txt", + }) + ).toEqual(true); + }); + + it('should return FALSE when WINDOWS wildcards paths have a wildcard in executable name', () => { + expect( + hasSimpleExecutableName({ + os: OperatingSystem.WINDOWS, + type: 'wildcard', + value: 'c:\\**\\pa*h.exe', + }) + ).toEqual(false); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/path_validations/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/path_validations/index.ts new file mode 100644 index 0000000000000..965a5b9fbe0fe --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/path_validations/index.ts @@ -0,0 +1,243 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const WILDCARD_WARNING = i18n.translate('utils.wildcardWarning', { + defaultMessage: `Using wildcards can impact Endpoint performance`, +}); + +export const FILEPATH_WARNING = i18n.translate('utils.filename.pathWarning', { + defaultMessage: `Path may be formed incorrectly; verify value`, +}); + +export enum ConditionEntryField { + HASH = 'process.hash.*', + PATH = 'process.executable.caseless', + SIGNER = 'process.Ext.code_signature', + SIGNER_MAC = 'process.code_signature', +} + +export enum EntryFieldType { + HASH = '.hash.', + EXECUTABLE = '.executable.caseless', + PATH = '.path', + SIGNER = '.code_signature', +} + +export type TrustedAppConditionEntryField = + | 'process.hash.*' + | 'process.executable.caseless' + | 'process.Ext.code_signature' + | 'process.code_signature'; + +export type BlocklistConditionEntryField = + | 'file.hash.*' + | 'file.path' + | 'file.Ext.code_signature' + | 'file.path.caseless'; +export type AllConditionEntryFields = + | TrustedAppConditionEntryField + | BlocklistConditionEntryField + | 'file.path.text'; + +export enum OperatingSystem { + LINUX = 'linux', + MAC = 'macos', + WINDOWS = 'windows', +} + +export type EntryTypes = 'match' | 'wildcard' | 'match_any'; +export type TrustedAppEntryTypes = Extract; +export type EventFiltersTypes = EntryTypes | 'exists' | 'nested'; + +export const validatePotentialWildcardInput = ({ + field = '', + os, + value = '', +}: { + field?: string; + os: OperatingSystem; + value?: string; +}): string | undefined => { + const textInput = value.trim(); + if (field === 'file.path.text') { + return validateFilePathInput({ os, value: textInput }); + } + return validateWildcardInput(textInput); +}; + +export const validateFilePathInput = ({ + os, + value, +}: { + os: OperatingSystem; + value: string; +}): string | undefined => { + const isValidFilePath = isPathValid({ + os, + field: 'file.path.text', + type: 'wildcard', + value, + }); + const hasSimpleFileName = hasSimpleExecutableName({ + os, + type: 'wildcard', + value, + }); + + if (!value.length) { + return FILEPATH_WARNING; + } + + if (isValidFilePath) { + if (hasSimpleFileName !== undefined && !hasSimpleFileName) { + return WILDCARD_WARNING; + } + } else { + return FILEPATH_WARNING; + } +}; + +export const validateWildcardInput = (value: string | string[]): string | undefined => { + const wildcardRegex = /[*?]/; + if (Array.isArray(value)) { + const doesAnyValueContainWildcardInput = value.some((v) => wildcardRegex.test(v)); + if (doesAnyValueContainWildcardInput) { + return WILDCARD_WARNING; + } + } else { + if (wildcardRegex.test(value)) { + return WILDCARD_WARNING; + } + } +}; + +export const validateHasWildcardWithWrongOperator = ({ + operator, + value, +}: { + operator: TrustedAppEntryTypes | EventFiltersTypes; + value: string | string[]; +}): boolean => { + if (operator !== 'wildcard' && validateWildcardInput(value)) { + return true; + } else { + return false; + } +}; + +export const hasSimpleExecutableName = ({ + os, + type, + value, +}: { + os: OperatingSystem; + type: EntryTypes; + value: string; +}): boolean | undefined => { + const separator = os === OperatingSystem.WINDOWS ? '\\' : '/'; + const lastString = value.split(separator).pop(); + if (!lastString) { + return; + } + if (type === 'wildcard') { + return (lastString.split('*').length || lastString.split('?').length) === 1; + } + return true; +}; + +export const isPathValid = ({ + os, + field, + type, + value, +}: { + os: OperatingSystem; + field: AllConditionEntryFields; + type: EntryTypes; + value: string; +}): boolean => { + const pathFields: AllConditionEntryFields[] = [ + 'process.executable.caseless', + 'file.path', + 'file.path.text', + ]; + if (pathFields.includes(field)) { + if (type === 'wildcard') { + return os === OperatingSystem.WINDOWS + ? isWindowsWildcardPathValid(value) + : isLinuxMacWildcardPathValid(value); + } + return doesPathMatchRegex({ value, os }); + } + return true; +}; + +const doesPathMatchRegex = ({ os, value }: { os: OperatingSystem; value: string }): boolean => { + if (os === OperatingSystem.WINDOWS) { + const filePathRegex = + /^[a-z]:(?:|\\\\[^<>:"'/\\|?*]+\\[^<>:"'/\\|?*]+|%\w+%|)[\\](?:[^<>:"'/\\|?*]+[\\/])*([^<>:"'/\\|?*])+$/i; + return filePathRegex.test(value); + } + return /^(\/|(\/[\w\-]+)+|\/[\w\-]+\.[\w]+|(\/[\w-]+)+\/[\w\-]+\.[\w]+)$/i.test(value); +}; + +const isWindowsWildcardPathValid = (path: string): boolean => { + const firstCharacter = path[0]; + const lastCharacter = path.slice(-1); + const trimmedValue = path.trim(); + const hasSlash = /\//.test(trimmedValue); + if (path.length === 0) { + return false; + } else if ( + hasSlash || + trimmedValue.length !== path.length || + firstCharacter === '^' || + lastCharacter === '\\' || + !hasWildcard({ path, isWindowsPath: true }) + ) { + return false; + } else { + return true; + } +}; + +const isLinuxMacWildcardPathValid = (path: string): boolean => { + const firstCharacter = path[0]; + const lastCharacter = path.slice(-1); + const trimmedValue = path.trim(); + if (path.length === 0) { + return false; + } else if ( + trimmedValue.length !== path.length || + firstCharacter !== '/' || + lastCharacter === '/' || + path.length > 1024 === true || + path.includes('//') === true || + !hasWildcard({ path, isWindowsPath: false }) + ) { + return false; + } else { + return true; + } +}; + +const hasWildcard = ({ + path, + isWindowsPath, +}: { + path: string; + isWindowsPath: boolean; +}): boolean => { + for (const pathComponent of path.split(isWindowsPath ? '\\' : '/')) { + if (/[\*|\?]+/.test(pathComponent) === true) { + return true; + } + } + return false; +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts new file mode 100644 index 0000000000000..d91eb687d86db --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts @@ -0,0 +1,83 @@ +/* + * 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 { transformDataToNdjson } from '.'; + +export const ANCHOR_DATE = '2020-02-20T03:57:54.037Z'; + +const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE) => ({ + author: [], + id: '7a7065d7-6e8b-4aae-8d20-c93613dec9f9', + created_at: new Date(anchorDate).toISOString(), + updated_at: new Date(anchorDate).toISOString(), + created_by: 'elastic', + description: 'some description', + enabled: true, + false_positives: ['false positive 1', 'false positive 2'], + from: 'now-6m', + immutable: false, + name: 'Query with a rule id', + query: 'user.name: root or user.name: admin', + references: ['test 1', 'test 2'], + severity: 'high', + severity_mapping: [], + updated_by: 'elastic_kibana', + tags: ['some fake tag 1', 'some fake tag 2'], + to: 'now', + type: 'query', + threat: [], + version: 1, + output_index: '.siem-signals-default', + max_signals: 100, + risk_score: 55, + risk_score_mapping: [], + language: 'kuery', + rule_id: 'query-rule-id', + interval: '5m', + exceptions_list: [], +}); + +describe('transformDataToNdjson', () => { + test('if rules are empty it returns an empty string', () => { + const ruleNdjson = transformDataToNdjson([]); + expect(ruleNdjson).toEqual(''); + }); + + test('single rule will transform with new line ending character for ndjson', () => { + const rule = getRulesSchemaMock(); + const ruleNdjson = transformDataToNdjson([rule]); + expect(ruleNdjson.endsWith('\n')).toBe(true); + }); + + test('multiple rules will transform with two new line ending characters for ndjson', () => { + const result1 = getRulesSchemaMock(); + const result2 = getRulesSchemaMock(); + result2.id = 'some other id'; + result2.rule_id = 'some other id'; + result2.name = 'Some other rule'; + + const ruleNdjson = transformDataToNdjson([result1, result2]); + // this is how we count characters in JavaScript :-) + const count = ruleNdjson.split('\n').length - 1; + expect(count).toBe(2); + }); + + test('you can parse two rules back out without errors', () => { + const result1 = getRulesSchemaMock(); + const result2 = getRulesSchemaMock(); + result2.id = 'some other id'; + result2.rule_id = 'some other id'; + result2.name = 'Some other rule'; + + const ruleNdjson = transformDataToNdjson([result1, result2]); + const ruleStrings = ruleNdjson.split('\n'); + const reParsed1 = JSON.parse(ruleStrings[0]); + const reParsed2 = JSON.parse(ruleStrings[1]); + expect(reParsed1).toEqual(result1); + expect(reParsed2).toEqual(result2); + }); +}); diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.ts b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.ts new file mode 100644 index 0000000000000..572b777731c48 --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const transformDataToNdjson = (data: unknown[]): string => { + if (data.length !== 0) { + const dataString = data.map((item) => JSON.stringify(item)).join('\n'); + return `${dataString}\n`; + } else { + return ''; + } +}; diff --git a/x-pack/solutions/security/packages/kbn-securitysolution-utils/tsconfig.json b/x-pack/solutions/security/packages/kbn-securitysolution-utils/tsconfig.json new file mode 100644 index 0000000000000..063735a114dad --- /dev/null +++ b/x-pack/solutions/security/packages/kbn-securitysolution-utils/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "kbn_references": [ + "@kbn/i18n", + "@kbn/esql-utils", + "@kbn/esql-ast", + "@kbn/esql-validation-autocomplete" + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/x-pack/solutions/security/plugins/asset_inventory/README.md b/x-pack/solutions/security/plugins/asset_inventory/README.md index e1dd9d4ac8900..313a45cec6f76 100755 --- a/x-pack/solutions/security/plugins/asset_inventory/README.md +++ b/x-pack/solutions/security/plugins/asset_inventory/README.md @@ -8,6 +8,14 @@ Centralized asset inventory experience within the Elastic Security solution. A c See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/CONTRIBUTING.md) for instructions setting up your development environment. +### Feature flag + +First, enable the `assetInventoryStoreEnabled` experimental feature flag by adding the following to your `kibana.dev.yml`: + +```yml +xpack.securitySolution.enableExperimental: ['assetInventoryStoreEnabled'] +``` + ## Testing For general guidelines, read [Kibana Testing Guide](https://www.elastic.co/guide/en/kibana/current/development-tests.html) for more details diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/server/routes/graph/route.ts b/x-pack/solutions/security/plugins/cloud_security_posture/server/routes/graph/route.ts index f9544b656f927..f655747815850 100644 --- a/x-pack/solutions/security/plugins/cloud_security_posture/server/routes/graph/route.ts +++ b/x-pack/solutions/security/plugins/cloud_security_posture/server/routes/graph/route.ts @@ -43,7 +43,7 @@ export const defineGraphRoute = (router: CspRouter) => const cspContext = await context.csp; const { nodesLimit, showUnknownTarget = false } = request.body; - const { eventIds, start, end, esQuery } = request.body.query as GraphRequest['query']; + const { originEventIds, start, end, esQuery } = request.body.query as GraphRequest['query']; const spaceId = (await cspContext.spaces?.spacesService?.getActiveSpace(request))?.id; try { @@ -53,7 +53,7 @@ export const defineGraphRoute = (router: CspRouter) => esClient: cspContext.esClient, }, query: { - eventIds, + originEventIds, spaceId, start, end, diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/server/routes/graph/v1.ts b/x-pack/solutions/security/plugins/cloud_security_posture/server/routes/graph/v1.ts index b14a2ba3e06a9..d506bb856e766 100644 --- a/x-pack/solutions/security/plugins/cloud_security_posture/server/routes/graph/v1.ts +++ b/x-pack/solutions/security/plugins/cloud_security_posture/server/routes/graph/v1.ts @@ -33,7 +33,8 @@ interface GraphEdge { action: string; targetIds: string[] | string; eventOutcome: string; - isAlert: boolean; + isOrigin: boolean; + isOriginAlert: boolean; } interface LabelEdges { @@ -46,10 +47,15 @@ interface GraphContextServices { esClient: IScopedClusterClient; } +interface OriginEventId { + id: string; + isAlert: boolean; +} + interface GetGraphParams { services: GraphContextServices; query: { - eventIds: string[]; + originEventIds: OriginEventId[]; spaceId?: string; start: string | number; end: string | number; @@ -61,11 +67,13 @@ interface GetGraphParams { export const getGraph = async ({ services: { esClient, logger }, - query: { eventIds, spaceId = 'default', start, end, esQuery }, + query: { originEventIds, spaceId = 'default', start, end, esQuery }, showUnknownTarget, nodesLimit, }: GetGraphParams): Promise> => { - logger.trace(`Fetching graph for [eventIds: ${eventIds.join(', ')}] in [spaceId: ${spaceId}]`); + logger.trace( + `Fetching graph for [originEventIds: ${originEventIds.join(', ')}] in [spaceId: ${spaceId}]` + ); const results = await fetchGraph({ esClient, @@ -73,7 +81,7 @@ export const getGraph = async ({ logger, start, end, - eventIds, + originEventIds, esQuery, }); @@ -132,7 +140,7 @@ const fetchGraph = async ({ logger, start, end, - eventIds, + originEventIds, showUnknownTarget, esQuery, }: { @@ -140,15 +148,21 @@ const fetchGraph = async ({ logger: Logger; start: string | number; end: string | number; - eventIds: string[]; + originEventIds: OriginEventId[]; showUnknownTarget: boolean; esQuery?: EsQuery; }): Promise> => { + const originAlertIds = originEventIds.filter((originEventId) => originEventId.isAlert); const query = `from logs-* | WHERE event.action IS NOT NULL AND actor.entity.id IS NOT NULL -| EVAL isAlert = ${ - eventIds.length > 0 - ? `event.id in (${eventIds.map((_id, idx) => `?al_id${idx}`).join(', ')})` +| EVAL isOrigin = ${ + originEventIds.length > 0 + ? `event.id in (${originEventIds.map((_id, idx) => `?og_id${idx}`).join(', ')})` + : 'false' + } +| EVAL isOriginAlert = isOrigin AND ${ + originAlertIds.length > 0 + ? `event.id in (${originAlertIds.map((_id, idx) => `?og_alrt_id${idx}`).join(', ')})` : 'false' } | STATS badge = COUNT(*), @@ -159,19 +173,26 @@ const fetchGraph = async ({ action = event.action, targetIds = target.entity.id, eventOutcome = event.outcome, - isAlert + isOrigin, + isOriginAlert | LIMIT 1000 -| SORT isAlert DESC`; +| SORT isOrigin DESC`; logger.trace(`Executing query [${query}]`); + const eventIds = originEventIds.map((originEventId) => originEventId.id); return await esClient.asCurrentUser.helpers .esql({ columnar: false, filter: buildDslFilter(eventIds, showUnknownTarget, start, end, esQuery), query, // @ts-ignore - types are not up to date - params: [...eventIds.map((id, idx) => ({ [`al_id${idx}`]: id }))], + params: [ + ...originEventIds.map((originEventId, idx) => ({ [`og_id${idx}`]: originEventId.id })), + ...originEventIds + .filter((originEventId) => originEventId.isAlert) + .map((originEventId, idx) => ({ [`og_alrt_id${idx}`]: originEventId.id })), + ], }) .toRecords(); }; @@ -238,7 +259,7 @@ const createNodes = (records: GraphEdge[], context: Omit ({ + acknowledged: true, +}); diff --git a/x-pack/plugins/lists/common/schemas/response/exception_export_details_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/exception_export_details_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/exception_export_details_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/exception_export_details_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/exception_list_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/exception_list_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_summary_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/exception_list_summary_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/exception_list_summary_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/exception_list_summary_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/found_all_list_items_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/found_all_list_items_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/found_all_list_items_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/found_all_list_items_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/found_exception_list_item_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/found_exception_list_item_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/found_exception_list_item_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/found_exception_list_item_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/found_exception_list_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/found_exception_list_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/found_exception_list_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/found_exception_list_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/found_list_item_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/found_list_item_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/found_list_item_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/found_list_item_schema.mock.ts diff --git a/x-pack/solutions/security/plugins/lists/common/schemas/response/found_list_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/found_list_schema.mock.ts new file mode 100644 index 0000000000000..1691221842d39 --- /dev/null +++ b/x-pack/solutions/security/plugins/lists/common/schemas/response/found_list_schema.mock.ts @@ -0,0 +1,18 @@ +/* + * 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 type { FoundListSchema } from '@kbn/securitysolution-io-ts-list-types'; + +import { getListResponseMock } from './list_schema.mock'; + +export const getFoundListSchemaMock = (): FoundListSchema => ({ + cursor: '123', + data: [getListResponseMock()], + page: 1, + per_page: 1, + total: 1, +}); diff --git a/x-pack/plugins/lists/common/schemas/response/found_lists_by_size_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/found_lists_by_size_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/found_lists_by_size_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/found_lists_by_size_schema.mock.ts diff --git a/x-pack/solutions/security/plugins/lists/common/schemas/response/list_item_index_exist_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/list_item_index_exist_schema.mock.ts new file mode 100644 index 0000000000000..afbb03cab870d --- /dev/null +++ b/x-pack/solutions/security/plugins/lists/common/schemas/response/list_item_index_exist_schema.mock.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ListItemIndexExistSchema } from '@kbn/securitysolution-io-ts-list-types'; + +export const getListItemIndexExistSchemaResponseMock = (): ListItemIndexExistSchema => ({ + list_index: true, + list_item_index: true, +}); diff --git a/x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/list_item_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/list_item_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/list_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/list_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/response/search_list_item_schema.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/response/search_list_item_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/response/search_list_item_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/response/search_list_item_schema.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/comment.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/comment.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/comment.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/comment.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/create_comment.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/create_comment.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/create_comment.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/create_comment.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/entries.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/entries.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/entries.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/entries.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/entry_exists.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/entry_exists.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/entry_exists.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/entry_exists.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/entry_list.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/entry_list.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/entry_list.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/entry_list.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/entry_match.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/entry_match.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/entry_match.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/entry_match.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/entry_match_any.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/entry_match_any.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/entry_match_any.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/entry_match_any.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/entry_match_wildcard.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/entry_match_wildcard.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/entry_match_wildcard.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/entry_nested.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/entry_nested.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/entry_nested.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/entry_nested.mock.ts diff --git a/x-pack/plugins/lists/common/schemas/types/update_comment.mock.ts b/x-pack/solutions/security/plugins/lists/common/schemas/types/update_comment.mock.ts similarity index 100% rename from x-pack/plugins/lists/common/schemas/types/update_comment.mock.ts rename to x-pack/solutions/security/plugins/lists/common/schemas/types/update_comment.mock.ts diff --git a/x-pack/solutions/security/plugins/lists/jest.config.js b/x-pack/solutions/security/plugins/lists/jest.config.js new file mode 100644 index 0000000000000..3bbf109f51ab5 --- /dev/null +++ b/x-pack/solutions/security/plugins/lists/jest.config.js @@ -0,0 +1,18 @@ +/* + * 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. + */ + +module.exports = { + collectCoverageFrom: [ + '/x-pack/solutions/security/plugins/lists/{common,public,server}/**/*.{ts,tsx}', + ], + coverageDirectory: + '/target/kibana-coverage/jest/x-pack/solutions/security/plugins/lists', + coverageReporters: ['text', 'html'], + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/solutions/security/plugins/lists'], +}; diff --git a/x-pack/plugins/lists/kibana.jsonc b/x-pack/solutions/security/plugins/lists/kibana.jsonc similarity index 100% rename from x-pack/plugins/lists/kibana.jsonc rename to x-pack/solutions/security/plugins/lists/kibana.jsonc diff --git a/x-pack/plugins/lists/public/common/empty_value.ts b/x-pack/solutions/security/plugins/lists/public/common/empty_value.ts similarity index 100% rename from x-pack/plugins/lists/public/common/empty_value.ts rename to x-pack/solutions/security/plugins/lists/public/common/empty_value.ts diff --git a/x-pack/plugins/lists/public/exceptions/api.test.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/api.test.ts similarity index 100% rename from x-pack/plugins/lists/public/exceptions/api.test.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/api.test.ts diff --git a/x-pack/plugins/lists/public/exceptions/components/__mock__/show_value_list_modal.mock.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/__mock__/show_value_list_modal.mock.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/__mock__/show_value_list_modal.mock.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/__mock__/show_value_list_modal.mock.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/and_or_badge/index.stories.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/index.stories.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/and_or_badge/index.stories.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/index.stories.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/and_or_badge/index.test.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/index.test.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/and_or_badge/index.test.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/index.test.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/and_or_badge/index.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/index.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/and_or_badge/index.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/index.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge.test.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge.test.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge.test.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge.test.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge_antenna.test.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge_antenna.test.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge_antenna.test.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge_antenna.test.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge_antenna.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge_antenna.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge_antenna.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/rounded_badge_antenna.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/and_or_badge/translations.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/translations.ts similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/and_or_badge/translations.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/and_or_badge/translations.ts diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/and_badge.test.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/and_badge.test.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/and_badge.test.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/and_badge.test.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/and_badge.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/and_badge.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/and_badge.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/and_badge.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/builder.stories.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/builder.stories.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/builder.stories.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/builder.stories.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_delete_button.test.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_delete_button.test.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/entry_delete_button.test.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_delete_button.test.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_delete_button.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_delete_button.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/entry_delete_button.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_delete_button.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.stories.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_renderer.stories.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.stories.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_renderer.stories.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.test.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/exception_item_renderer.test.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.test.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/exception_item_renderer.test.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.test.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/exception_items_renderer.test.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.test.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/exception_items_renderer.test.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/helpers.test.ts similarity index 99% rename from x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/helpers.test.ts index 2c0f8b198b384..c5afe22bb73c8 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/helpers.test.ts @@ -1669,7 +1669,7 @@ describe('Exception builder helpers', () => { }); describe('#filterExceptionItems', () => { - // Please see `x-pack/plugins/lists/public/exceptions/transforms.ts` doc notes + // Please see `x-pack/solutions/security/plugins/lists/public/exceptions/transforms.ts` doc notes // for context around the temporary `id` test('it correctly validates entries that include a temporary `id`', () => { const output: ExceptionsBuilderReturnExceptionItem[] = filterExceptionItems([ diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/index.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/index.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/index.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/index.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/logic_buttons.test.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/logic_buttons.test.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/logic_buttons.test.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/logic_buttons.test.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/logic_buttons.tsx b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/logic_buttons.tsx similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/logic_buttons.tsx rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/logic_buttons.tsx diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/reducer.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/reducer.ts similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/reducer.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/reducer.ts diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/selectors.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/selectors.ts similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/selectors.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/selectors.ts diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/translations.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/translations.ts similarity index 100% rename from x-pack/plugins/lists/public/exceptions/components/builder/translations.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/components/builder/translations.ts diff --git a/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.test.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/hooks/persist_exception_item.test.ts similarity index 96% rename from x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.test.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/hooks/persist_exception_item.test.ts index 95ca6285f0d74..029488f850d43 100644 --- a/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_item.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/exceptions/hooks/persist_exception_item.test.ts @@ -17,7 +17,7 @@ import { getExceptionListItemSchemaMock } from '../../../common/schemas/response const mockKibanaHttpService = coreMock.createStart().http; -// TODO: Port this test over to packages/kbn-securitysolution-list-hooks/src/use_persist_exception_item/index.test.ts once the other mocks are added to the kbn package system +// TODO: Port this test over to x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_item/index.test.ts once the other mocks are added to the kbn package system describe('usePersistExceptionItem', () => { let addExceptionListItemSpy: jest.SpyInstance>; diff --git a/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.test.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/hooks/persist_exception_list.test.ts similarity index 95% rename from x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.test.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/hooks/persist_exception_list.test.ts index c27888b6d8cc6..159426d711601 100644 --- a/x-pack/plugins/lists/public/exceptions/hooks/persist_exception_list.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/exceptions/hooks/persist_exception_list.test.ts @@ -18,7 +18,7 @@ const mockKibanaHttpService = coreMock.createStart().http; jest.mock('@kbn/securitysolution-list-api'); -// TODO: Port this to the kbn package of: packages/kbn-securitysolution-list-hooks/src/use_persist_exception_list/index.test.ts once the kibana mocks are ported +// TODO: Port this to the kbn package of: x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_persist_exception_list/index.test.ts once the kibana mocks are ported describe('usePersistExceptionList', () => { const onError = jest.fn(); diff --git a/x-pack/plugins/lists/public/exceptions/hooks/use_api.test.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/hooks/use_api.test.ts similarity index 99% rename from x-pack/plugins/lists/public/exceptions/hooks/use_api.test.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/hooks/use_api.test.ts index a980261ba5f86..2ceaab63cc044 100644 --- a/x-pack/plugins/lists/public/exceptions/hooks/use_api.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/exceptions/hooks/use_api.test.ts @@ -32,7 +32,7 @@ jest.mock('uuid', () => ({ const mockKibanaHttpService = coreMock.createStart().http; -// TODO: Once the mocks are figured out and the types are moved into kbn core this test should be moved next to the file: packages/kbn-securitysolution-list-hooks/src/use_api/index.test.ts +// TODO: Once the mocks are figured out and the types are moved into kbn core this test should be moved next to the file: x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_api/index.test.ts describe('useApi', () => { const onErrorMock = jest.fn(); diff --git a/x-pack/plugins/lists/public/exceptions/hooks/use_exception_lists.test.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/hooks/use_exception_lists.test.ts similarity index 97% rename from x-pack/plugins/lists/public/exceptions/hooks/use_exception_lists.test.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/hooks/use_exception_lists.test.ts index 6c684d199e538..db01cc54e855f 100644 --- a/x-pack/plugins/lists/public/exceptions/hooks/use_exception_lists.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/exceptions/hooks/use_exception_lists.test.ts @@ -20,7 +20,7 @@ const mockKibanaHttpService = coreMock.createStart().http; const mockKibanaNotificationsService = coreMock.createStart().notifications; jest.mock('@kbn/securitysolution-list-api'); -// TODO: Move this test to the kbn package: packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.test.ts once mocks are ported over +// TODO: Move this test to the kbn package: x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.test.ts once mocks are ported over describe('useExceptionLists', () => { beforeEach(() => { diff --git a/x-pack/plugins/lists/public/exceptions/transforms.test.ts b/x-pack/solutions/security/plugins/lists/public/exceptions/transforms.test.ts similarity index 100% rename from x-pack/plugins/lists/public/exceptions/transforms.test.ts rename to x-pack/solutions/security/plugins/lists/public/exceptions/transforms.test.ts diff --git a/x-pack/plugins/lists/public/index.ts b/x-pack/solutions/security/plugins/lists/public/index.ts similarity index 100% rename from x-pack/plugins/lists/public/index.ts rename to x-pack/solutions/security/plugins/lists/public/index.ts diff --git a/x-pack/plugins/lists/public/lists/hooks/use_create_list_index.test.ts b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_create_list_index.test.ts similarity index 93% rename from x-pack/plugins/lists/public/lists/hooks/use_create_list_index.test.ts rename to x-pack/solutions/security/plugins/lists/public/lists/hooks/use_create_list_index.test.ts index 7021d49940f26..806d8b6337088 100644 --- a/x-pack/plugins/lists/public/lists/hooks/use_create_list_index.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_create_list_index.test.ts @@ -15,7 +15,7 @@ import { createQueryWrapperMock } from '../mocks/query_wrapper'; jest.mock('@kbn/securitysolution-list-api'); -// TODO: This test should be ported to the package: packages/kbn-securitysolution-list-hooks/src/use_create_list_index/index.test.ts once we have mocks in kbn packages +// TODO: This test should be ported to the package: x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_create_list_index/index.test.ts once we have mocks in kbn packages const { wrapper: queryWrapper, queryClient } = createQueryWrapperMock(); diff --git a/x-pack/plugins/lists/public/lists/hooks/use_delete_list.test.ts b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_delete_list.test.ts similarity index 86% rename from x-pack/plugins/lists/public/lists/hooks/use_delete_list.test.ts rename to x-pack/solutions/security/plugins/lists/public/lists/hooks/use_delete_list.test.ts index 7a339f3e12a4a..72276e7c474de 100644 --- a/x-pack/plugins/lists/public/lists/hooks/use_delete_list.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_delete_list.test.ts @@ -14,7 +14,7 @@ import { getListResponseMock } from '../../../common/schemas/response/list_schem jest.mock('@kbn/securitysolution-list-api'); -// TODO: This test should be ported to the package: packages/kbn-securitysolution-list-hooks/src/use_delete_list/index.test.ts once we have mocks in kbn packages +// TODO: This test should be ported to the package: x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_delete_list/index.test.ts once we have mocks in kbn packages describe('useDeleteList', () => { let httpMock: ReturnType; diff --git a/x-pack/plugins/lists/public/lists/hooks/use_export_list.test.ts b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_export_list.test.ts similarity index 86% rename from x-pack/plugins/lists/public/lists/hooks/use_export_list.test.ts rename to x-pack/solutions/security/plugins/lists/public/lists/hooks/use_export_list.test.ts index 8f08ad5c8bd03..6cafd4958f7a7 100644 --- a/x-pack/plugins/lists/public/lists/hooks/use_export_list.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_export_list.test.ts @@ -12,7 +12,7 @@ import { httpServiceMock } from '@kbn/core/public/mocks'; jest.mock('@kbn/securitysolution-list-api'); -// TODO: Move this test to the kbn package: packages/kbn-securitysolution-list-hooks/src/use_export_list/index.ts once Mocks are ported from Kibana +// TODO: Move this test to the kbn package: x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_export_list/index.ts once Mocks are ported from Kibana describe('useExportList', () => { let httpMock: ReturnType; diff --git a/x-pack/plugins/lists/public/lists/hooks/use_import_list.test.ts b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_import_list.test.ts similarity index 94% rename from x-pack/plugins/lists/public/lists/hooks/use_import_list.test.ts rename to x-pack/solutions/security/plugins/lists/public/lists/hooks/use_import_list.test.ts index d56478a0321be..00a3a39f1f1aa 100644 --- a/x-pack/plugins/lists/public/lists/hooks/use_import_list.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_import_list.test.ts @@ -14,7 +14,7 @@ import { getListResponseMock } from '../../../common/schemas/response/list_schem jest.mock('@kbn/securitysolution-list-api'); -// TODO: Port this test over to: packages/kbn-securitysolution-list-hooks/src/use_import_list/index.ts once mocks are moved to packages +// TODO: Port this test over to: x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_import_list/index.ts once mocks are moved to packages describe('useImportList', () => { let httpMock: ReturnType; diff --git a/x-pack/plugins/lists/public/lists/hooks/use_read_list_index.test.ts b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_read_list_index.test.ts similarity index 91% rename from x-pack/plugins/lists/public/lists/hooks/use_read_list_index.test.ts rename to x-pack/solutions/security/plugins/lists/public/lists/hooks/use_read_list_index.test.ts index 643ac2df5b05b..cd36b6d531061 100644 --- a/x-pack/plugins/lists/public/lists/hooks/use_read_list_index.test.ts +++ b/x-pack/solutions/security/plugins/lists/public/lists/hooks/use_read_list_index.test.ts @@ -17,7 +17,7 @@ jest.mock('@kbn/securitysolution-list-api'); const { wrapper: queryWrapper } = createQueryWrapperMock(); -// TODO: Port this code over to the package: packages/kbn-securitysolution-list-hooks/src/use_read_list_index/index.test.ts once kibana has mocks in packages +// TODO: Port this code over to the package: x-pack/solutions/security/packages/kbn-securitysolution-list-hooks/src/use_read_list_index/index.test.ts once kibana has mocks in packages // FLAKY: https://github.com/elastic/kibana/issues/178026 describe.skip('useReadListIndex', () => { diff --git a/x-pack/plugins/lists/public/lists/mocks/query_wrapper.tsx b/x-pack/solutions/security/plugins/lists/public/lists/mocks/query_wrapper.tsx similarity index 100% rename from x-pack/plugins/lists/public/lists/mocks/query_wrapper.tsx rename to x-pack/solutions/security/plugins/lists/public/lists/mocks/query_wrapper.tsx diff --git a/x-pack/plugins/lists/public/lists/types.ts b/x-pack/solutions/security/plugins/lists/public/lists/types.ts similarity index 100% rename from x-pack/plugins/lists/public/lists/types.ts rename to x-pack/solutions/security/plugins/lists/public/lists/types.ts diff --git a/x-pack/plugins/lists/public/plugin.ts b/x-pack/solutions/security/plugins/lists/public/plugin.ts similarity index 100% rename from x-pack/plugins/lists/public/plugin.ts rename to x-pack/solutions/security/plugins/lists/public/plugin.ts diff --git a/x-pack/plugins/lists/public/shared_exports.ts b/x-pack/solutions/security/plugins/lists/public/shared_exports.ts similarity index 100% rename from x-pack/plugins/lists/public/shared_exports.ts rename to x-pack/solutions/security/plugins/lists/public/shared_exports.ts diff --git a/x-pack/plugins/lists/public/types.ts b/x-pack/solutions/security/plugins/lists/public/types.ts similarity index 100% rename from x-pack/plugins/lists/public/types.ts rename to x-pack/solutions/security/plugins/lists/public/types.ts diff --git a/x-pack/plugins/lists/scripts/storybook.js b/x-pack/solutions/security/plugins/lists/scripts/storybook.js similarity index 100% rename from x-pack/plugins/lists/scripts/storybook.js rename to x-pack/solutions/security/plugins/lists/scripts/storybook.js diff --git a/x-pack/plugins/lists/server/config.mock.ts b/x-pack/solutions/security/plugins/lists/server/config.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/config.mock.ts rename to x-pack/solutions/security/plugins/lists/server/config.mock.ts diff --git a/x-pack/plugins/lists/server/config.test.ts b/x-pack/solutions/security/plugins/lists/server/config.test.ts similarity index 100% rename from x-pack/plugins/lists/server/config.test.ts rename to x-pack/solutions/security/plugins/lists/server/config.test.ts diff --git a/x-pack/plugins/lists/server/config.ts b/x-pack/solutions/security/plugins/lists/server/config.ts similarity index 100% rename from x-pack/plugins/lists/server/config.ts rename to x-pack/solutions/security/plugins/lists/server/config.ts diff --git a/x-pack/plugins/lists/server/error_with_status_code.ts b/x-pack/solutions/security/plugins/lists/server/error_with_status_code.ts similarity index 100% rename from x-pack/plugins/lists/server/error_with_status_code.ts rename to x-pack/solutions/security/plugins/lists/server/error_with_status_code.ts diff --git a/x-pack/plugins/lists/server/get_space_id.test.ts b/x-pack/solutions/security/plugins/lists/server/get_space_id.test.ts similarity index 100% rename from x-pack/plugins/lists/server/get_space_id.test.ts rename to x-pack/solutions/security/plugins/lists/server/get_space_id.test.ts diff --git a/x-pack/plugins/lists/server/get_space_id.ts b/x-pack/solutions/security/plugins/lists/server/get_space_id.ts similarity index 100% rename from x-pack/plugins/lists/server/get_space_id.ts rename to x-pack/solutions/security/plugins/lists/server/get_space_id.ts diff --git a/x-pack/plugins/lists/server/get_user.test.ts b/x-pack/solutions/security/plugins/lists/server/get_user.test.ts similarity index 100% rename from x-pack/plugins/lists/server/get_user.test.ts rename to x-pack/solutions/security/plugins/lists/server/get_user.test.ts diff --git a/x-pack/plugins/lists/server/get_user.ts b/x-pack/solutions/security/plugins/lists/server/get_user.ts similarity index 100% rename from x-pack/plugins/lists/server/get_user.ts rename to x-pack/solutions/security/plugins/lists/server/get_user.ts diff --git a/x-pack/plugins/lists/server/handlers/create_exception_list_handler.ts b/x-pack/solutions/security/plugins/lists/server/handlers/create_exception_list_handler.ts similarity index 100% rename from x-pack/plugins/lists/server/handlers/create_exception_list_handler.ts rename to x-pack/solutions/security/plugins/lists/server/handlers/create_exception_list_handler.ts diff --git a/x-pack/plugins/lists/server/index.ts b/x-pack/solutions/security/plugins/lists/server/index.ts similarity index 100% rename from x-pack/plugins/lists/server/index.ts rename to x-pack/solutions/security/plugins/lists/server/index.ts diff --git a/x-pack/plugins/lists/server/mocks.ts b/x-pack/solutions/security/plugins/lists/server/mocks.ts similarity index 100% rename from x-pack/plugins/lists/server/mocks.ts rename to x-pack/solutions/security/plugins/lists/server/mocks.ts diff --git a/x-pack/plugins/lists/server/plugin.ts b/x-pack/solutions/security/plugins/lists/server/plugin.ts similarity index 100% rename from x-pack/plugins/lists/server/plugin.ts rename to x-pack/solutions/security/plugins/lists/server/plugin.ts diff --git a/x-pack/plugins/lists/server/routes/create_endpoint_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/create_endpoint_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/create_endpoint_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/create_endpoint_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/create_endpoint_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/create_endpoint_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/create_exception_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/create_exception_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/create_exception_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/create_exception_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/create_exception_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/delete_endpoint_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/delete_endpoint_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/delete_exception_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/delete_exception_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/delete_exception_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/delete_exception_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/delete_exception_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/duplicate_exception_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/duplicate_exception_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/duplicate_exception_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/duplicate_exception_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/endpoint_disallowed_fields.ts b/x-pack/solutions/security/plugins/lists/server/routes/endpoint_disallowed_fields.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/endpoint_disallowed_fields.ts rename to x-pack/solutions/security/plugins/lists/server/routes/endpoint_disallowed_fields.ts diff --git a/x-pack/plugins/lists/server/routes/export_exception_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/export_exception_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/export_exception_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/export_exception_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/find_endpoint_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/find_endpoint_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/find_exception_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/find_exception_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/find_exception_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/find_exception_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/find_exception_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/import_exceptions_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/import_exceptions_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/import_exceptions_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/import_exceptions_route.ts diff --git a/x-pack/plugins/lists/server/routes/index.ts b/x-pack/solutions/security/plugins/lists/server/routes/index.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/index.ts rename to x-pack/solutions/security/plugins/lists/server/routes/index.ts diff --git a/x-pack/plugins/lists/server/routes/init_routes.ts b/x-pack/solutions/security/plugins/lists/server/routes/init_routes.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/init_routes.ts rename to x-pack/solutions/security/plugins/lists/server/routes/init_routes.ts diff --git a/x-pack/plugins/lists/server/routes/internal/create_exception_filter_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/internal/create_exception_filter_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/internal/create_exception_filter_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/internal/create_exception_filter_route.ts diff --git a/x-pack/plugins/lists/server/routes/internal/create_exceptions_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/internal/create_exceptions_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/internal/create_exceptions_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/internal/create_exceptions_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/internal/find_lists_by_size_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/internal/find_lists_by_size_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/internal/find_lists_by_size_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/internal/find_lists_by_size_route.ts diff --git a/x-pack/plugins/lists/server/routes/list/create_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list/create_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list/create_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list/create_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/list/delete_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list/delete_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list/delete_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list/delete_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/list/import_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list/import_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list/import_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list/import_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/list/patch_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list/patch_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list/patch_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list/patch_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/list/read_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list/read_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list/read_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list/read_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/list/update_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list/update_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list/update_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list/update_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_index/create_list_index_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_index/create_list_index_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_index/delete_list_index_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_index/delete_list_index_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_index/export_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_index/export_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_index/find_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_index/find_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_index/find_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_index/find_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_index/read_list_index_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_index/read_list_index_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_item/create_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_item/create_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_item/delete_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_item/delete_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_item/find_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_item/find_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_item/patch_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_item/patch_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_item/read_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_item/read_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_item/update_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_item/update_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.mock.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_privileges/read_list_privileges_route.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.mock.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_privileges/read_list_privileges_route.mock.ts diff --git a/x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts diff --git a/x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/read_endpoint_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/read_endpoint_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/read_exception_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/read_exception_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/read_exception_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/read_exception_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/read_exception_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/summary_exception_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/summary_exception_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/summary_exception_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/update_endpoint_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/update_endpoint_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/update_exception_list_item_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/update_exception_list_item_route.ts diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts b/x-pack/solutions/security/plugins/lists/server/routes/update_exception_list_route.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/update_exception_list_route.ts rename to x-pack/solutions/security/plugins/lists/server/routes/update_exception_list_route.ts diff --git a/x-pack/plugins/lists/server/routes/utils/build_siem_response.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/build_siem_response.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/build_siem_response.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/build_siem_response.ts diff --git a/x-pack/plugins/lists/server/routes/utils/create_stream_from_buffer.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/create_stream_from_buffer.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/create_stream_from_buffer.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/create_stream_from_buffer.ts diff --git a/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/get_error_message_exception_list.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/get_error_message_exception_list.ts diff --git a/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list_item.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/get_error_message_exception_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/get_error_message_exception_list_item.ts diff --git a/x-pack/plugins/lists/server/routes/utils/get_exception_list_client.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/get_exception_list_client.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/get_exception_list_client.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/get_exception_list_client.ts diff --git a/x-pack/plugins/lists/server/routes/utils/get_internal_list_client.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/get_internal_list_client.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/get_internal_list_client.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/get_internal_list_client.ts diff --git a/x-pack/plugins/lists/server/routes/utils/get_list_client.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/get_list_client.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/get_list_client.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/get_list_client.ts diff --git a/x-pack/plugins/lists/server/routes/utils/index.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/index.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/index.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/index.ts diff --git a/x-pack/plugins/lists/server/routes/utils/route_validation.test.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/route_validation.test.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/route_validation.test.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/route_validation.test.ts diff --git a/x-pack/plugins/lists/server/routes/utils/route_validation.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/route_validation.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/route_validation.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/route_validation.ts diff --git a/x-pack/plugins/lists/server/routes/utils/validate_comments_to_update.test.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/validate_comments_to_update.test.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/validate_comments_to_update.test.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/validate_comments_to_update.test.ts diff --git a/x-pack/plugins/lists/server/routes/utils/validate_comments_to_update.ts b/x-pack/solutions/security/plugins/lists/server/routes/utils/validate_comments_to_update.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/utils/validate_comments_to_update.ts rename to x-pack/solutions/security/plugins/lists/server/routes/utils/validate_comments_to_update.ts diff --git a/x-pack/plugins/lists/server/routes/validate.ts b/x-pack/solutions/security/plugins/lists/server/routes/validate.ts similarity index 100% rename from x-pack/plugins/lists/server/routes/validate.ts rename to x-pack/solutions/security/plugins/lists/server/routes/validate.ts diff --git a/x-pack/plugins/lists/server/saved_objects/exception_list.ts b/x-pack/solutions/security/plugins/lists/server/saved_objects/exception_list.ts similarity index 100% rename from x-pack/plugins/lists/server/saved_objects/exception_list.ts rename to x-pack/solutions/security/plugins/lists/server/saved_objects/exception_list.ts diff --git a/x-pack/plugins/lists/server/saved_objects/index.ts b/x-pack/solutions/security/plugins/lists/server/saved_objects/index.ts similarity index 100% rename from x-pack/plugins/lists/server/saved_objects/index.ts rename to x-pack/solutions/security/plugins/lists/server/saved_objects/index.ts diff --git a/x-pack/plugins/lists/server/saved_objects/init_saved_objects.ts b/x-pack/solutions/security/plugins/lists/server/saved_objects/init_saved_objects.ts similarity index 100% rename from x-pack/plugins/lists/server/saved_objects/init_saved_objects.ts rename to x-pack/solutions/security/plugins/lists/server/saved_objects/init_saved_objects.ts diff --git a/x-pack/plugins/lists/server/saved_objects/migrations.test.ts b/x-pack/solutions/security/plugins/lists/server/saved_objects/migrations.test.ts similarity index 100% rename from x-pack/plugins/lists/server/saved_objects/migrations.test.ts rename to x-pack/solutions/security/plugins/lists/server/saved_objects/migrations.test.ts diff --git a/x-pack/plugins/lists/server/saved_objects/migrations.ts b/x-pack/solutions/security/plugins/lists/server/saved_objects/migrations.ts similarity index 100% rename from x-pack/plugins/lists/server/saved_objects/migrations.ts rename to x-pack/solutions/security/plugins/lists/server/saved_objects/migrations.ts diff --git a/x-pack/plugins/lists/server/schemas/common/get_shard.mock.ts b/x-pack/solutions/security/plugins/lists/server/schemas/common/get_shard.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/common/get_shard.mock.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/common/get_shard.mock.ts diff --git a/x-pack/plugins/lists/server/schemas/common/schemas.test.ts b/x-pack/solutions/security/plugins/lists/server/schemas/common/schemas.test.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/common/schemas.test.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/common/schemas.test.ts diff --git a/x-pack/plugins/lists/server/schemas/common/schemas.ts b/x-pack/solutions/security/plugins/lists/server/schemas/common/schemas.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/common/schemas.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/common/schemas.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_query/create_es_bulk_type.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/create_es_bulk_type.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_query/create_es_bulk_type.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/create_es_bulk_type.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_query/index.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_query/index.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_query/index_es_list_item_schema.mock.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index_es_list_item_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_query/index_es_list_item_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index_es_list_item_schema.mock.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_query/index_es_list_item_schema.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index_es_list_item_schema.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_query/index_es_list_item_schema.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index_es_list_item_schema.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_query/index_es_list_schema.mock.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index_es_list_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_query/index_es_list_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index_es_list_schema.mock.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_query/index_es_list_schema.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index_es_list_schema.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_query/index_es_list_schema.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/index_es_list_schema.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_query/update_es_list_item_schema.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/update_es_list_item_schema.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_query/update_es_list_item_schema.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/update_es_list_item_schema.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_query/update_es_list_schema.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/update_es_list_schema.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_query/update_es_list_schema.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_query/update_es_list_schema.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_response/index.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/index.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_response/index.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/index.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.mock.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.mock.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.test.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.test.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.test.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.test.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_item_schema.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.mock.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_schema.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.mock.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_schema.mock.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.test.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_schema.test.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.test.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_schema.test.ts diff --git a/x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.ts b/x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_schema.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/elastic_response/search_es_list_schema.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/elastic_response/search_es_list_schema.ts diff --git a/x-pack/plugins/lists/server/schemas/saved_objects/exceptions_list_so_schema.ts b/x-pack/solutions/security/plugins/lists/server/schemas/saved_objects/exceptions_list_so_schema.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/saved_objects/exceptions_list_so_schema.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/saved_objects/exceptions_list_so_schema.ts diff --git a/x-pack/plugins/lists/server/schemas/saved_objects/index.ts b/x-pack/solutions/security/plugins/lists/server/schemas/saved_objects/index.ts similarity index 100% rename from x-pack/plugins/lists/server/schemas/saved_objects/index.ts rename to x-pack/solutions/security/plugins/lists/server/schemas/saved_objects/index.ts diff --git a/x-pack/plugins/lists/server/scripts/check_env_variables.sh b/x-pack/solutions/security/plugins/lists/server/scripts/check_env_variables.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/check_env_variables.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/check_env_variables.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_all_exception_lists.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_all_exception_lists.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_all_exception_lists.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_all_exception_lists.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_endpoint_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_endpoint_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_endpoint_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_endpoint_list_item.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_endpoint_list_item_by_id.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_endpoint_list_item_by_id.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_endpoint_list_item_by_id.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_endpoint_list_item_by_id.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_exception_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_exception_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_exception_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_exception_list.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_exception_list_by_id.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_exception_list_by_id.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_exception_list_by_id.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_exception_list_by_id.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_exception_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_exception_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_exception_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_exception_list_item.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_exception_list_item_by_id.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_exception_list_item_by_id.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_exception_list_item_by_id.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_exception_list_item_by_id.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_list.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_list_index.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_list_index.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_list_index.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_list_index.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_list_item_by_id.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_list_item_by_id.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_list_item_by_id.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_list_item_by_id.sh diff --git a/x-pack/plugins/lists/server/scripts/delete_list_item_by_value.sh b/x-pack/solutions/security/plugins/lists/server/scripts/delete_list_item_by_value.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/delete_list_item_by_value.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/delete_list_item_by_value.sh diff --git a/x-pack/plugins/lists/server/scripts/download_load_lists_example.sh b/x-pack/solutions/security/plugins/lists/server/scripts/download_load_lists_example.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/download_load_lists_example.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/download_load_lists_example.sh diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/files/import.ndjson b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/files/import.ndjson similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/files/import.ndjson rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/files/import.ndjson diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/endpoint_list_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/endpoint_list_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/endpoint_list_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/endpoint_list_item.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_agnostic.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_agnostic.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_agnostic.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_agnostic.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_auto_id.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_auto_id.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_auto_id.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_auto_id.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_detection.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_detection.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_detection.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_detection.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_agnostic.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_agnostic.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_agnostic.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_agnostic.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_auto_id.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_auto_id.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_auto_id.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_auto_id.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_detection_auto_id.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_detection_auto_id.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_detection_auto_id.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_detection_auto_id.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_with_bad_ip_list.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_with_bad_ip_list.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_with_bad_ip_list.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_with_bad_ip_list.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_with_list.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_with_list.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_with_list.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/exception_list_item_with_list.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_1.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_1.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_1.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_1.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_2_agnostic.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_2_agnostic.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_2_agnostic.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_2_agnostic.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_3.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_3.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_3.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_detection_3.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_1_multi_value_list.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_1_multi_value_list.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_1_multi_value_list.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_1_multi_value_list.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_1_non_value_list.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_1_non_value_list.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_1_non_value_list.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_1_non_value_list.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_2_multi_value_list.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_2_multi_value_list.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_2_multi_value_list.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_2_multi_value_list.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_2_non_value_list.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_2_non_value_list.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_2_non_value_list.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_2_non_value_list.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_3_non_value_list.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_3_non_value_list.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_3_non_value_list.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_3_non_value_list.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_3_single_value_list.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_3_single_value_list.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_3_single_value_list.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/references/exception_list_item_3_single_value_list.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/trusted_app_list_item_agnostic.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/trusted_app_list_item_agnostic.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/new/trusted_app_list_item_agnostic.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/new/trusted_app_list_item_agnostic.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/updates/simple_update.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/updates/simple_update.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update_agnostic.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/updates/simple_update_agnostic.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update_agnostic.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/updates/simple_update_agnostic.json diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/updates/simple_update_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/exception_lists/updates/simple_update_item.json diff --git a/x-pack/plugins/lists/server/scripts/export_list_items.sh b/x-pack/solutions/security/plugins/lists/server/scripts/export_list_items.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/export_list_items.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/export_list_items.sh diff --git a/x-pack/plugins/lists/server/scripts/export_list_items_to_file.sh b/x-pack/solutions/security/plugins/lists/server/scripts/export_list_items_to_file.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/export_list_items_to_file.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/export_list_items_to_file.sh diff --git a/x-pack/plugins/lists/server/scripts/find_endpoint_list_items.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_endpoint_list_items.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_endpoint_list_items.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_endpoint_list_items.sh diff --git a/x-pack/plugins/lists/server/scripts/find_exception_list_items.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_exception_list_items.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_exception_list_items.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_exception_list_items.sh diff --git a/x-pack/plugins/lists/server/scripts/find_exception_list_items_by_filter.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_exception_list_items_by_filter.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_exception_list_items_by_filter.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_exception_list_items_by_filter.sh diff --git a/x-pack/plugins/lists/server/scripts/find_exception_lists.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_exception_lists.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_exception_lists.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_exception_lists.sh diff --git a/x-pack/plugins/lists/server/scripts/find_exception_lists_by_filter.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_exception_lists_by_filter.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_exception_lists_by_filter.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_exception_lists_by_filter.sh diff --git a/x-pack/plugins/lists/server/scripts/find_list_items.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_list_items.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_list_items.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_list_items.sh diff --git a/x-pack/plugins/lists/server/scripts/find_list_items_with_cursor.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_list_items_with_cursor.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_list_items_with_cursor.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_list_items_with_cursor.sh diff --git a/x-pack/plugins/lists/server/scripts/find_list_items_with_sort.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_list_items_with_sort.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_list_items_with_sort.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_list_items_with_sort.sh diff --git a/x-pack/plugins/lists/server/scripts/find_list_items_with_sort_cursor.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_list_items_with_sort_cursor.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_list_items_with_sort_cursor.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_list_items_with_sort_cursor.sh diff --git a/x-pack/plugins/lists/server/scripts/find_lists.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_lists.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_lists.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_lists.sh diff --git a/x-pack/plugins/lists/server/scripts/find_lists_with_cursor.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_lists_with_cursor.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_lists_with_cursor.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_lists_with_cursor.sh diff --git a/x-pack/plugins/lists/server/scripts/find_lists_with_filter.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_lists_with_filter.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_lists_with_filter.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_lists_with_filter.sh diff --git a/x-pack/plugins/lists/server/scripts/find_lists_with_sort.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_lists_with_sort.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_lists_with_sort.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_lists_with_sort.sh diff --git a/x-pack/plugins/lists/server/scripts/find_lists_with_sort_cursor.sh b/x-pack/solutions/security/plugins/lists/server/scripts/find_lists_with_sort_cursor.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/find_lists_with_sort_cursor.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/find_lists_with_sort_cursor.sh diff --git a/x-pack/plugins/lists/server/scripts/get_endpoint_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_endpoint_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_endpoint_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_endpoint_list_item.sh diff --git a/x-pack/plugins/lists/server/scripts/get_endpoint_list_item_by_id.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_endpoint_list_item_by_id.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_endpoint_list_item_by_id.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_endpoint_list_item_by_id.sh diff --git a/x-pack/plugins/lists/server/scripts/get_exception_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_exception_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_exception_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_exception_list.sh diff --git a/x-pack/plugins/lists/server/scripts/get_exception_list_by_id.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_exception_list_by_id.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_exception_list_by_id.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_exception_list_by_id.sh diff --git a/x-pack/plugins/lists/server/scripts/get_exception_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_exception_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_exception_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_exception_list_item.sh diff --git a/x-pack/plugins/lists/server/scripts/get_exception_list_item_by_id.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_exception_list_item_by_id.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_exception_list_item_by_id.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_exception_list_item_by_id.sh diff --git a/x-pack/plugins/lists/server/scripts/get_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_list.sh diff --git a/x-pack/plugins/lists/server/scripts/get_list_item_by_id.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_list_item_by_id.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_list_item_by_id.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_list_item_by_id.sh diff --git a/x-pack/plugins/lists/server/scripts/get_list_item_by_value.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_list_item_by_value.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_list_item_by_value.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_list_item_by_value.sh diff --git a/x-pack/plugins/lists/server/scripts/get_privileges.sh b/x-pack/solutions/security/plugins/lists/server/scripts/get_privileges.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/get_privileges.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/get_privileges.sh diff --git a/x-pack/plugins/lists/server/scripts/hard_reset.sh b/x-pack/solutions/security/plugins/lists/server/scripts/hard_reset.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/hard_reset.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/hard_reset.sh diff --git a/x-pack/plugins/lists/server/scripts/import_exception_lists.sh b/x-pack/solutions/security/plugins/lists/server/scripts/import_exception_lists.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/import_exception_lists.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/import_exception_lists.sh diff --git a/x-pack/plugins/lists/server/scripts/import_list_items.sh b/x-pack/solutions/security/plugins/lists/server/scripts/import_list_items.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/import_list_items.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/import_list_items.sh diff --git a/x-pack/plugins/lists/server/scripts/import_list_items_by_filename.sh b/x-pack/solutions/security/plugins/lists/server/scripts/import_list_items_by_filename.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/import_list_items_by_filename.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/import_list_items_by_filename.sh diff --git a/x-pack/plugins/lists/server/scripts/lists/files/binary.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/binary.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/binary.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/binary.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/boolean.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/boolean.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/boolean.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/boolean.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/byte.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/byte.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/byte.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/byte.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/date.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/date.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/date.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/date.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/date_nanos.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/date_nanos.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/date_nanos.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/date_nanos.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/date_range.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/date_range.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/date_range.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/date_range.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/date_range_custom_format.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/date_range_custom_format.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/date_range_custom_format.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/date_range_custom_format.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/double.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/double.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/double.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/double.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/double_range.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/double_range.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/double_range.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/double_range.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/float.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/float.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/float.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/float.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/float_range.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/float_range.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/float_range.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/float_range.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/geo_hash.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/geo_hash.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/geo_hash.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/geo_hash.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/geo_point.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/geo_point.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/geo_point.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/geo_point.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/geo_point_wkt.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/geo_point_wkt.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/geo_point_wkt.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/geo_point_wkt.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/half_float.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/half_float.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/half_float.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/half_float.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/hosts.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/hosts.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/hosts.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/hosts.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/integer.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/integer.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/integer.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/integer.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/integer_range.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/integer_range.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/integer_range.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/integer_range.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/ip_range.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/ip_range.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/ip_range.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/ip_range.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/ip_range_cidr.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/ip_range_cidr.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/ip_range_cidr.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/ip_range_cidr.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/ip_range_mixed.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/ip_range_mixed.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/ip_range_mixed.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/ip_range_mixed.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/ips.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/ips.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/ips.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/ips.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/long.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/long.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/long.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/long.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/long_range.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/long_range.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/long_range.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/long_range.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/short.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/short.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/short.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/short.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/files/text.txt b/x-pack/solutions/security/plugins/lists/server/scripts/lists/files/text.txt similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/files/text.txt rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/files/text.txt diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/binary_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/binary_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/binary_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/binary_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/boolean_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/boolean_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/boolean_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/boolean_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/byte_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/byte_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/byte_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/byte_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/date_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/date_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/date_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/date_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/date_nanos_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/date_nanos_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/date_nanos_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/date_nanos_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/date_range_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/date_range_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/date_range_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/date_range_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/double_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/double_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/double_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/double_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/double_range_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/double_range_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/double_range_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/double_range_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/float_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/float_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/float_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/float_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/float_range_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/float_range_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/float_range_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/float_range_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/geo_point_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/geo_point_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/geo_point_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/geo_point_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/geo_shape_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/geo_shape_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/geo_shape_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/geo_shape_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/half_float_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/half_float_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/half_float_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/half_float_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/integer_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/integer_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/integer_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/integer_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/integer_range_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/integer_range_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/integer_range_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/integer_range_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/ip_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/ip_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/ip_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/ip_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/ip_item_everything.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/ip_item_everything.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/ip_item_everything.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/ip_item_everything.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/ip_range_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/ip_range_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/ip_range_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/ip_range_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/keyword_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/keyword_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/keyword_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/keyword_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/long_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/long_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/long_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/long_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/long_range_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/long_range_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/long_range_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/long_range_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/shape_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/shape_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/shape_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/shape_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/short_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/short_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/short_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/short_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/items/text_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/text_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/items/text_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/items/text_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/list_ip_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/list_ip_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/list_ip_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/list_ip_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/list_keyword_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/list_keyword_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/list_keyword_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/list_keyword_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/auto_id.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/auto_id.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/auto_id.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/auto_id.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/binary.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/binary.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/binary.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/binary.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/boolean.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/boolean.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/boolean.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/boolean.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/byte.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/byte.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/byte.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/byte.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/date.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/date.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/date.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/date.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/date_nanos.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/date_nanos.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/date_nanos.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/date_nanos.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/date_range.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/date_range.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/date_range.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/date_range.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/date_range_custom_format.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/date_range_custom_format.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/date_range_custom_format.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/date_range_custom_format.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/double.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/double.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/double.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/double.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/double_range.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/double_range.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/double_range.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/double_range.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/everything.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/everything.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/everything.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/everything.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/float.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/float.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/float.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/float.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/float_range.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/float_range.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/float_range.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/float_range.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/geo_point.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/geo_point.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/geo_point.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/geo_point.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/geo_shape.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/geo_shape.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/geo_shape.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/geo_shape.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/half_float.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/half_float.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/half_float.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/half_float.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/integer.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/integer.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/integer.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/integer.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/integer_range.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/integer_range.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/integer_range.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/integer_range.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/ip.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/ip.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/ip.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/ip.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/ip_custom_format.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/ip_custom_format.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/ip_custom_format.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/ip_custom_format.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/ip_no_id.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/ip_no_id.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/ip_no_id.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/ip_no_id.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/ip_range.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/ip_range.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/ip_range.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/ip_range.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/keyword.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/keyword.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/keyword.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/keyword.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/keyword_custom_format.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/keyword_custom_format.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/keyword_custom_format.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/keyword_custom_format.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/long.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/long.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/long.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/long.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/shape.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/shape.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/shape.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/shape.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/short.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/short.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/short.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/short.json diff --git a/x-pack/plugins/lists/server/scripts/lists/new/lists/text.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/text.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/new/lists/text.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/new/lists/text.json diff --git a/x-pack/plugins/lists/server/scripts/lists/patches/ip_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/patches/ip_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/patches/ip_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/patches/ip_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/patches/simplest_updated_name.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/patches/simplest_updated_name.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/patches/simplest_updated_name.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/patches/simplest_updated_name.json diff --git a/x-pack/plugins/lists/server/scripts/lists/updates/ip_item.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/updates/ip_item.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/updates/ip_item.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/updates/ip_item.json diff --git a/x-pack/plugins/lists/server/scripts/lists/updates/simple_update.json b/x-pack/solutions/security/plugins/lists/server/scripts/lists/updates/simple_update.json similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists/updates/simple_update.json rename to x-pack/solutions/security/plugins/lists/server/scripts/lists/updates/simple_update.json diff --git a/x-pack/plugins/lists/server/scripts/lists_index_exists.sh b/x-pack/solutions/security/plugins/lists/server/scripts/lists_index_exists.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/lists_index_exists.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/lists_index_exists.sh diff --git a/x-pack/plugins/lists/server/scripts/patch_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/patch_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/patch_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/patch_list.sh diff --git a/x-pack/plugins/lists/server/scripts/patch_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/patch_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/patch_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/patch_list_item.sh diff --git a/x-pack/plugins/lists/server/scripts/post_endpoint_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/post_endpoint_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/post_endpoint_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/post_endpoint_list.sh diff --git a/x-pack/plugins/lists/server/scripts/post_endpoint_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/post_endpoint_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/post_endpoint_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/post_endpoint_list_item.sh diff --git a/x-pack/plugins/lists/server/scripts/post_exception_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/post_exception_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/post_exception_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/post_exception_list.sh diff --git a/x-pack/plugins/lists/server/scripts/post_exception_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/post_exception_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/post_exception_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/post_exception_list_item.sh diff --git a/x-pack/plugins/lists/server/scripts/post_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/post_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/post_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/post_list.sh diff --git a/x-pack/plugins/lists/server/scripts/post_list_index.sh b/x-pack/solutions/security/plugins/lists/server/scripts/post_list_index.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/post_list_index.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/post_list_index.sh diff --git a/x-pack/plugins/lists/server/scripts/post_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/post_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/post_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/post_list_item.sh diff --git a/x-pack/plugins/lists/server/scripts/post_x_exception_list_items.sh b/x-pack/solutions/security/plugins/lists/server/scripts/post_x_exception_list_items.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/post_x_exception_list_items.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/post_x_exception_list_items.sh diff --git a/x-pack/plugins/lists/server/scripts/quick_start.sh b/x-pack/solutions/security/plugins/lists/server/scripts/quick_start.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/quick_start.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/quick_start.sh diff --git a/x-pack/plugins/lists/server/scripts/quick_start_value_list_references.sh b/x-pack/solutions/security/plugins/lists/server/scripts/quick_start_value_list_references.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/quick_start_value_list_references.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/quick_start_value_list_references.sh diff --git a/x-pack/plugins/lists/server/scripts/summary_exception_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/summary_exception_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/summary_exception_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/summary_exception_list.sh diff --git a/x-pack/plugins/lists/server/scripts/update_endpoint_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/update_endpoint_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/update_endpoint_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/update_endpoint_item.sh diff --git a/x-pack/plugins/lists/server/scripts/update_exception_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/update_exception_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/update_exception_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/update_exception_list.sh diff --git a/x-pack/plugins/lists/server/scripts/update_exception_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/update_exception_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/update_exception_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/update_exception_list_item.sh diff --git a/x-pack/plugins/lists/server/scripts/update_list.sh b/x-pack/solutions/security/plugins/lists/server/scripts/update_list.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/update_list.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/update_list.sh diff --git a/x-pack/plugins/lists/server/scripts/update_list_item.sh b/x-pack/solutions/security/plugins/lists/server/scripts/update_list_item.sh similarity index 100% rename from x-pack/plugins/lists/server/scripts/update_list_item.sh rename to x-pack/solutions/security/plugins/lists/server/scripts/update_list_item.sh diff --git a/x-pack/plugins/lists/server/services/exception_lists/build_exception_filter.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/build_exception_filter.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/build_exception_filter.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/build_exception_filter.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/build_exception_filter.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/build_exception_filter.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/build_exception_filter.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/build_exception_filter.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/bulk_create_exception_list_items.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/bulk_create_exception_list_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/bulk_create_exception_list_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/bulk_create_exception_list_items.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/close_point_in_time.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/close_point_in_time.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/close_point_in_time.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/close_point_in_time.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/create_endpoint_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/create_endpoint_list.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_trusted_apps_list.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/create_endpoint_trusted_apps_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/create_endpoint_trusted_apps_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/create_endpoint_trusted_apps_list.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/create_exception_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/create_exception_list.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/create_exception_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/create_exception_list_item.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/delete_exception_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/delete_exception_list.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/duplicate_exception_list.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/duplicate_exception_list.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/duplicate_exception_list.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/duplicate_exception_list.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/duplicate_exception_list.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/duplicate_exception_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/duplicate_exception_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/duplicate_exception_list.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/exception_list_client.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/exception_list_client.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/exception_list_client.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/exception_list_client.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/exception_list_client_types.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/exception_list_client_types.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/export_exception_list_and_items.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/export_exception_list_and_items.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/export_exception_list_and_items.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/export_exception_list_and_items.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/export_exception_list_and_items.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/export_exception_list_and_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/export_exception_list_and_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/export_exception_list_and_items.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/find_exception_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_item.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_item_point_in_time_finder.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_item_point_in_time_finder.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/find_exception_list_item_point_in_time_finder.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_item_point_in_time_finder.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_items.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/find_exception_list_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_items.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_items_point_in_time_finder.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_items_point_in_time_finder.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/find_exception_list_items_point_in_time_finder.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_items_point_in_time_finder.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_point_in_time_finder.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_point_in_time_finder.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/find_exception_list_point_in_time_finder.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_exception_list_point_in_time_finder.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_value_list_exception_list_items.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_value_list_exception_list_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/find_value_list_exception_list_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_value_list_exception_list_items.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_value_list_exception_list_items_point_in_time_finder.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_value_list_exception_list_items_point_in_time_finder.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/find_value_list_exception_list_items_point_in_time_finder.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/find_value_list_exception_list_items_point_in_time_finder.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/get_exception_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/get_exception_list.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/get_exception_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/get_exception_list_item.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/get_exception_list_summary.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/get_exception_list_summary.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/get_exception_list_summary.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/import_exception_list_and_items.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/import_exception_list_and_items.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/import_exception_list_and_items.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/import_exception_list_and_items.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/import_exception_list_and_items.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/import_exception_list_and_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/import_exception_list_and_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/import_exception_list_and_items.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/index.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/index.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/index.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/index.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/open_point_in_time.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/open_point_in_time.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/open_point_in_time.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/open_point_in_time.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/update_exception_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/update_exception_list.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/update_exception_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/update_exception_list_item.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/update_overwrite_exception_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/update_overwrite_exception_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/update_overwrite_exception_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/update_overwrite_exception_list_item.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/errors.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/errors.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/errors.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/errors.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/get_exception_list_filter.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_lists_item_filter.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/get_exception_lists_item_filter.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_lists_item_filter.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/get_exception_lists_item_filter.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_lists_item_filter.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/get_exception_lists_item_filter.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/get_exception_lists_item_filter.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/get_exception_lists_item_filter.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_items.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_items.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_items.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_items.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_items.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_items.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_lists.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_lists.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_lists.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_lists.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_lists.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_lists.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_lists.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_create_imported_lists.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_items.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_items.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_items.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_items.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_items.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_items.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_lists.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_lists.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_lists.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_lists.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_lists.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_lists.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_lists.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/bulk_update_imported_lists.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/create_exceptions_stream_logic.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/create_exceptions_stream_logic.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/create_exceptions_stream_logic.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/create_exceptions_stream_logic.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/create_exceptions_stream_logic.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/create_exceptions_stream_logic.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/create_exceptions_stream_logic.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/create_exceptions_stream_logic.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_items.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_items.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_items.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_items.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_items.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_items.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_lists.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_lists.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_lists.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_lists.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_lists.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_lists.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_lists.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/dedupe_incoming_lists.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/delete_list_items_to_overwrite.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/delete_list_items_to_overwrite.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/delete_list_items_to_overwrite.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/delete_list_items_to_overwrite.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/delete_list_items_to_overwrite.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/delete_list_items_to_overwrite.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/delete_list_items_to_overwrite.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/delete_list_items_to_overwrite.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_item_types.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_item_types.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_item_types.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_item_types.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_item_types.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_item_types.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_item_types.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_item_types.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/find_all_exception_list_types.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/import_exception_list_items.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/import_exception_list_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/import_exception_list_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/import_exception_list_items.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/import_exception_lists.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/import_exception_lists.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/import_exception_lists.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/import_exception_lists.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/is_import_regular.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/is_import_regular.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/is_import_regular.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/is_import_regular.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/is_import_regular.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/is_import_regular.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/is_import_regular.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/is_import_regular.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_exception_items_to_create_or_update.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_exception_items_to_create_or_update.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_exception_items_to_create_or_update.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_exception_items_to_create_or_update.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_exception_items_to_create_update.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_exception_items_to_create_update.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_exception_items_to_create_update.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_exception_items_to_create_update.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_exception_lists_to_create_or_update.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_exception_lists_to_create_or_update.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_exception_lists_to_create_or_update.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_exception_lists_to_create_or_update.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_exception_lists_to_create_update.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_exception_lists_to_create_update.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_exception_lists_to_create_update.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_exception_lists_to_create_update.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_import_by_namespace.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_import_by_namespace.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_import_by_namespace.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_import_by_namespace.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_import_by_namespace.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_import_by_namespace.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_import_by_namespace.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_import_by_namespace.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_import_responses.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_import_responses.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_import_responses.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_import_responses.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_import_responses.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_import_responses.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/import/sort_import_responses.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/import/sort_import_responses.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/index.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/index.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/index.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/index.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/index.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/index.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/index.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/index.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/validate_data.test.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/validate_data.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/validate_data.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/validate_data.test.ts diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils/validate_data.ts b/x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/validate_data.ts similarity index 100% rename from x-pack/plugins/lists/server/services/exception_lists/utils/validate_data.ts rename to x-pack/solutions/security/plugins/lists/server/services/exception_lists/utils/validate_data.ts diff --git a/x-pack/plugins/lists/server/services/extension_points/errors.ts b/x-pack/solutions/security/plugins/lists/server/services/extension_points/errors.ts similarity index 100% rename from x-pack/plugins/lists/server/services/extension_points/errors.ts rename to x-pack/solutions/security/plugins/lists/server/services/extension_points/errors.ts diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.test.ts b/x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/extension_points/extension_point_storage.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage.test.ts diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.ts b/x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage.ts similarity index 100% rename from x-pack/plugins/lists/server/services/extension_points/extension_point_storage.ts rename to x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage.ts diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts b/x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.ts b/x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage_client.ts similarity index 100% rename from x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.ts rename to x-pack/solutions/security/plugins/lists/server/services/extension_points/extension_point_storage_client.ts diff --git a/x-pack/plugins/lists/server/services/extension_points/index.ts b/x-pack/solutions/security/plugins/lists/server/services/extension_points/index.ts similarity index 100% rename from x-pack/plugins/lists/server/services/extension_points/index.ts rename to x-pack/solutions/security/plugins/lists/server/services/extension_points/index.ts diff --git a/x-pack/plugins/lists/server/services/extension_points/types.ts b/x-pack/solutions/security/plugins/lists/server/services/extension_points/types.ts similarity index 100% rename from x-pack/plugins/lists/server/services/extension_points/types.ts rename to x-pack/solutions/security/plugins/lists/server/services/extension_points/types.ts diff --git a/x-pack/plugins/lists/server/services/items/buffer_lines.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/buffer_lines.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/buffer_lines.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/buffer_lines.test.ts diff --git a/x-pack/plugins/lists/server/services/items/buffer_lines.ts b/x-pack/solutions/security/plugins/lists/server/services/items/buffer_lines.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/buffer_lines.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/buffer_lines.ts diff --git a/x-pack/plugins/lists/server/services/items/create_list_item.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/create_list_item.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/create_list_item.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/create_list_item.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/create_list_item.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/create_list_item.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/create_list_item.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/create_list_item.test.ts diff --git a/x-pack/plugins/lists/server/services/items/create_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/items/create_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/create_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/create_list_item.ts diff --git a/x-pack/plugins/lists/server/services/items/create_list_items_bulk.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/create_list_items_bulk.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/create_list_items_bulk.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/create_list_items_bulk.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/create_list_items_bulk.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/create_list_items_bulk.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/create_list_items_bulk.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/create_list_items_bulk.test.ts diff --git a/x-pack/plugins/lists/server/services/items/create_list_items_bulk.ts b/x-pack/solutions/security/plugins/lists/server/services/items/create_list_items_bulk.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/create_list_items_bulk.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/create_list_items_bulk.ts diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/delete_list_item.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/delete_list_item.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item.test.ts diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/delete_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item.ts diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item_by_value.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/delete_list_item_by_value.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item_by_value.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item_by_value.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/delete_list_item_by_value.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item_by_value.test.ts diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.ts b/x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item_by_value.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/delete_list_item_by_value.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/delete_list_item_by_value.ts diff --git a/x-pack/plugins/lists/server/services/items/find_all_list_items.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/find_all_list_items.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/find_all_list_items.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/find_all_list_items.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/find_all_list_items.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/find_all_list_items.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/find_all_list_items.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/find_all_list_items.test.ts diff --git a/x-pack/plugins/lists/server/services/items/find_all_list_items.ts b/x-pack/solutions/security/plugins/lists/server/services/items/find_all_list_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/find_all_list_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/find_all_list_items.ts diff --git a/x-pack/plugins/lists/server/services/items/find_list_item.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/find_list_item.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/find_list_item.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/find_list_item.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/find_list_item.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/find_list_item.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/find_list_item.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/find_list_item.test.ts diff --git a/x-pack/plugins/lists/server/services/items/find_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/items/find_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/find_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/find_list_item.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item.test.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_value.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_value.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_by_value.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_value.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_value.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_value.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_by_value.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_value.test.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_value.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_value.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_by_value.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_value.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_values.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_by_values.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_values.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_values.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_by_values.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_values.test.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_values.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_by_values.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_index.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_index.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_index.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_index.test.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_index.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_index.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_index.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_index.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_template.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_template.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_template.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_template.test.ts diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_template.ts b/x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_template.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/get_list_item_template.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/get_list_item_template.ts diff --git a/x-pack/plugins/lists/server/services/items/index.ts b/x-pack/solutions/security/plugins/lists/server/services/items/index.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/index.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/index.ts diff --git a/x-pack/plugins/lists/server/services/items/list_item_mappings.json b/x-pack/solutions/security/plugins/lists/server/services/items/list_item_mappings.json similarity index 100% rename from x-pack/plugins/lists/server/services/items/list_item_mappings.json rename to x-pack/solutions/security/plugins/lists/server/services/items/list_item_mappings.json diff --git a/x-pack/plugins/lists/server/services/items/list_item_policy.json b/x-pack/solutions/security/plugins/lists/server/services/items/list_item_policy.json similarity index 100% rename from x-pack/plugins/lists/server/services/items/list_item_policy.json rename to x-pack/solutions/security/plugins/lists/server/services/items/list_item_policy.json diff --git a/x-pack/plugins/lists/server/services/items/search_list_item_by_values.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/search_list_item_by_values.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/search_list_item_by_values.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/search_list_item_by_values.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/search_list_item_by_values.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/search_list_item_by_values.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/search_list_item_by_values.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/search_list_item_by_values.test.ts diff --git a/x-pack/plugins/lists/server/services/items/search_list_item_by_values.ts b/x-pack/solutions/security/plugins/lists/server/services/items/search_list_item_by_values.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/search_list_item_by_values.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/search_list_item_by_values.ts diff --git a/x-pack/plugins/lists/server/services/items/test_readable.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/test_readable.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/test_readable.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/test_readable.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/update_list_item.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/update_list_item.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/update_list_item.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/update_list_item.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/update_list_item.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/update_list_item.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/update_list_item.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/update_list_item.test.ts diff --git a/x-pack/plugins/lists/server/services/items/update_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/items/update_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/update_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/update_list_item.ts diff --git a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts diff --git a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/write_lines_to_bulk_list_items.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/write_lines_to_bulk_list_items.test.ts diff --git a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts b/x-pack/solutions/security/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts diff --git a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.test.ts b/x-pack/solutions/security/plugins/lists/server/services/items/write_list_items_to_stream.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/write_list_items_to_stream.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/write_list_items_to_stream.test.ts diff --git a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts b/x-pack/solutions/security/plugins/lists/server/services/items/write_list_items_to_stream.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/write_list_items_to_stream.ts diff --git a/x-pack/plugins/lists/server/services/items/write_list_items_to_streams.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/items/write_list_items_to_streams.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/items/write_list_items_to_streams.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/items/write_list_items_to_streams.mock.ts diff --git a/x-pack/plugins/lists/server/services/lists/create_list.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/create_list.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/create_list.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/create_list.mock.ts diff --git a/x-pack/plugins/lists/server/services/lists/create_list.test.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/create_list.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/create_list.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/create_list.test.ts diff --git a/x-pack/plugins/lists/server/services/lists/create_list.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/create_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/create_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/create_list.ts diff --git a/x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts diff --git a/x-pack/plugins/lists/server/services/lists/delete_list.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/delete_list.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/delete_list.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/delete_list.mock.ts diff --git a/x-pack/plugins/lists/server/services/lists/delete_list.test.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/delete_list.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/delete_list.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/delete_list.test.ts diff --git a/x-pack/plugins/lists/server/services/lists/delete_list.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/delete_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/delete_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/delete_list.ts diff --git a/x-pack/plugins/lists/server/services/lists/find_list.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/find_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/find_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/find_list.ts diff --git a/x-pack/plugins/lists/server/services/lists/get_list.test.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/get_list.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/get_list.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/get_list.test.ts diff --git a/x-pack/plugins/lists/server/services/lists/get_list.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/get_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/get_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/get_list.ts diff --git a/x-pack/plugins/lists/server/services/lists/get_list_index.test.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/get_list_index.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/get_list_index.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/get_list_index.test.ts diff --git a/x-pack/plugins/lists/server/services/lists/get_list_index.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/get_list_index.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/get_list_index.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/get_list_index.ts diff --git a/x-pack/plugins/lists/server/services/lists/get_list_template.test.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/get_list_template.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/get_list_template.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/get_list_template.test.ts diff --git a/x-pack/plugins/lists/server/services/lists/get_list_template.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/get_list_template.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/get_list_template.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/get_list_template.ts diff --git a/x-pack/plugins/lists/server/services/lists/index.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/index.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/index.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/index.ts diff --git a/x-pack/plugins/lists/server/services/lists/list_client.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/list_client.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/list_client.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/list_client.mock.ts diff --git a/x-pack/plugins/lists/server/services/lists/list_client.test.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/list_client.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/list_client.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/list_client.test.ts diff --git a/x-pack/plugins/lists/server/services/lists/list_client.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/list_client.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/list_client.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/list_client.ts diff --git a/x-pack/plugins/lists/server/services/lists/list_client_types.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/list_client_types.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/list_client_types.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/list_client_types.ts diff --git a/x-pack/plugins/lists/server/services/lists/list_mappings.json b/x-pack/solutions/security/plugins/lists/server/services/lists/list_mappings.json similarity index 100% rename from x-pack/plugins/lists/server/services/lists/list_mappings.json rename to x-pack/solutions/security/plugins/lists/server/services/lists/list_mappings.json diff --git a/x-pack/plugins/lists/server/services/lists/list_policy.json b/x-pack/solutions/security/plugins/lists/server/services/lists/list_policy.json similarity index 100% rename from x-pack/plugins/lists/server/services/lists/list_policy.json rename to x-pack/solutions/security/plugins/lists/server/services/lists/list_policy.json diff --git a/x-pack/plugins/lists/server/services/lists/types.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/types.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/types.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/types.ts diff --git a/x-pack/plugins/lists/server/services/lists/update_list.mock.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/update_list.mock.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/update_list.mock.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/update_list.mock.ts diff --git a/x-pack/plugins/lists/server/services/lists/update_list.test.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/update_list.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/update_list.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/update_list.test.ts diff --git a/x-pack/plugins/lists/server/services/lists/update_list.ts b/x-pack/solutions/security/plugins/lists/server/services/lists/update_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/lists/update_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/lists/update_list.ts diff --git a/x-pack/plugins/lists/server/services/utils/calculate_scroll_math.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/calculate_scroll_math.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/calculate_scroll_math.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/calculate_scroll_math.ts diff --git a/x-pack/plugins/lists/server/services/utils/check_version_conflict.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/check_version_conflict.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/check_version_conflict.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/check_version_conflict.ts diff --git a/x-pack/plugins/lists/server/services/utils/encode_decode_cursor.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/encode_decode_cursor.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/encode_decode_cursor.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/encode_decode_cursor.ts diff --git a/x-pack/plugins/lists/server/services/utils/escape_query.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/escape_query.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/escape_query.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/escape_query.ts diff --git a/x-pack/plugins/lists/server/services/utils/find_source_type.test.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/find_source_type.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/find_source_type.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/find_source_type.test.ts diff --git a/x-pack/plugins/lists/server/services/utils/find_source_type.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/find_source_type.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/find_source_type.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/find_source_type.ts diff --git a/x-pack/plugins/lists/server/services/utils/find_source_value.test.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/find_source_value.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/find_source_value.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/find_source_value.test.ts diff --git a/x-pack/plugins/lists/server/services/utils/find_source_value.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/find_source_value.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/find_source_value.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/find_source_value.ts diff --git a/x-pack/plugins/lists/server/services/utils/get_query_filter.test.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/get_query_filter.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/get_query_filter.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/get_query_filter.test.ts diff --git a/x-pack/plugins/lists/server/services/utils/get_query_filter.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/get_query_filter.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/get_query_filter.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/get_query_filter.ts diff --git a/x-pack/plugins/lists/server/services/utils/get_query_filter_from_type_value.test.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/get_query_filter_from_type_value.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/get_query_filter_from_type_value.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/get_query_filter_from_type_value.test.ts diff --git a/x-pack/plugins/lists/server/services/utils/get_query_filter_from_type_value.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/get_query_filter_from_type_value.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/get_query_filter_from_type_value.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/get_query_filter_from_type_value.ts diff --git a/x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/get_search_after_scroll.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/get_search_after_scroll.ts diff --git a/x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts diff --git a/x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts diff --git a/x-pack/plugins/lists/server/services/utils/get_source_with_tie_breaker.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/get_source_with_tie_breaker.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/get_source_with_tie_breaker.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/get_source_with_tie_breaker.ts diff --git a/x-pack/plugins/lists/server/services/utils/index.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/index.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/index.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/index.ts diff --git a/x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/scroll_to_start_page.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/scroll_to_start_page.ts diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.test.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.test.ts diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_to_list.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_to_list.ts diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list_item.test.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_to_list_item.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/transform_elastic_to_list_item.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_to_list_item.test.ts diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list_item.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_to_list_item.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/transform_elastic_to_list_item.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/transform_elastic_to_list_item.ts diff --git a/x-pack/plugins/lists/server/services/utils/transform_list_item_to_elastic_query.test.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/transform_list_item_to_elastic_query.test.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/transform_list_item_to_elastic_query.test.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/transform_list_item_to_elastic_query.test.ts diff --git a/x-pack/plugins/lists/server/services/utils/transform_list_item_to_elastic_query.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/transform_list_item_to_elastic_query.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/transform_list_item_to_elastic_query.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/transform_list_item_to_elastic_query.ts diff --git a/x-pack/plugins/lists/server/services/utils/wait_until_document_indexed.ts b/x-pack/solutions/security/plugins/lists/server/services/utils/wait_until_document_indexed.ts similarity index 100% rename from x-pack/plugins/lists/server/services/utils/wait_until_document_indexed.ts rename to x-pack/solutions/security/plugins/lists/server/services/utils/wait_until_document_indexed.ts diff --git a/x-pack/plugins/lists/server/types.ts b/x-pack/solutions/security/plugins/lists/server/types.ts similarity index 100% rename from x-pack/plugins/lists/server/types.ts rename to x-pack/solutions/security/plugins/lists/server/types.ts diff --git a/x-pack/solutions/security/plugins/lists/tsconfig.json b/x-pack/solutions/security/plugins/lists/tsconfig.json new file mode 100644 index 0000000000000..c0f751d665ee8 --- /dev/null +++ b/x-pack/solutions/security/plugins/lists/tsconfig.json @@ -0,0 +1,50 @@ +{ + "extends": "../../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + // have to declare *.json explicitly due to https://github.com/microsoft/TypeScript/issues/25636 + "server/**/*.json" + ], + "kbn_references": [ + "@kbn/core", + "@kbn/spaces-plugin", + "@kbn/security-plugin", + "@kbn/unified-search-plugin", + "@kbn/securitysolution-io-ts-list-types", + "@kbn/securitysolution-list-constants", + "@kbn/securitysolution-list-hooks", + "@kbn/securitysolution-list-api", + "@kbn/securitysolution-lists-common", + "@kbn/securitysolution-exceptions-common", + "@kbn/securitysolution-endpoint-exceptions-common", + "@kbn/kibana-react-plugin", + "@kbn/i18n", + "@kbn/data-plugin", + "@kbn/securitysolution-list-utils", + "@kbn/securitysolution-utils", + "@kbn/es-query", + "@kbn/i18n-react", + "@kbn/securitysolution-autocomplete", + "@kbn/config-schema", + "@kbn/securitysolution-io-ts-utils", + "@kbn/core-http-server", + "@kbn/securitysolution-es-utils", + "@kbn/securitysolution-io-ts-types", + "@kbn/std", + "@kbn/utils", + "@kbn/logging-mocks", + "@kbn/utility-types", + "@kbn/core-elasticsearch-client-server-mocks", + "@kbn/core-saved-objects-server", + "@kbn/zod-helpers", + "@kbn/core-security-server", + "@kbn/core-http-server-mocks", + "@kbn/core-http-server-utils" + ], + "exclude": ["target/**/*"] +} diff --git a/x-pack/solutions/security/plugins/security_solution/common/api/endpoint/actions/common/response_actions.ts b/x-pack/solutions/security/plugins/security_solution/common/api/endpoint/actions/common/response_actions.ts index 56b1fafdb5a71..3a765e0c83134 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/api/endpoint/actions/common/response_actions.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/api/endpoint/actions/common/response_actions.ts @@ -17,6 +17,7 @@ import { GetProcessesRouteRequestSchema } from '../response_actions/running_proc import { KillProcessRouteRequestSchema } from '../response_actions/kill_process'; import { SuspendProcessRouteRequestSchema } from '../response_actions/suspend_process'; import { UploadActionRequestSchema } from '../response_actions/upload'; +import { RunScriptActionRequestSchema } from '../response_actions/run_script'; export const ResponseActionBodySchema = schema.oneOf([ IsolateRouteRequestSchema.body, @@ -28,6 +29,7 @@ export const ResponseActionBodySchema = schema.oneOf([ ExecuteActionRequestSchema.body, UploadActionRequestSchema.body, ScanActionRequestSchema.body, + RunScriptActionRequestSchema.body, ]); export type ResponseActionsRequestBody = TypeOf; diff --git a/x-pack/solutions/security/plugins/security_solution/common/api/endpoint/actions/response_actions/run_script/run_script.ts b/x-pack/solutions/security/plugins/security_solution/common/api/endpoint/actions/response_actions/run_script/run_script.ts index dfa88941b34e0..95c035e866884 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/api/endpoint/actions/response_actions/run_script/run_script.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/api/endpoint/actions/response_actions/run_script/run_script.ts @@ -26,27 +26,27 @@ export const RunScriptActionRequestSchema = { /** * The script to run */ - Raw: schema.maybe(NonEmptyString), + raw: schema.maybe(NonEmptyString), /** * The path to the script on the host to run */ - HostPath: schema.maybe(NonEmptyString), + hostPath: schema.maybe(NonEmptyString), /** * The path to the script in the cloud to run */ - CloudFile: schema.maybe(NonEmptyString), + cloudFile: schema.maybe(NonEmptyString), /** * The command line to run */ - CommandLine: schema.maybe(NonEmptyString), + commandLine: schema.maybe(NonEmptyString), /** * The max timeout value before the command is killed. Number represents milliseconds */ - Timeout: schema.maybe(schema.number({ min: 1 })), + timeout: schema.maybe(schema.number({ min: 1 })), }, { validate: (params) => { - if (!params.Raw && !params.HostPath && !params.CloudFile) { + if (!params.raw && !params.hostPath && !params.cloudFile) { return 'At least one of Raw, HostPath, or CloudFile must be provided'; } }, diff --git a/x-pack/solutions/security/plugins/security_solution/common/endpoint/service/response_actions/type_guards.ts b/x-pack/solutions/security/plugins/security_solution/common/endpoint/service/response_actions/type_guards.ts index 707be0a4d1e65..ece0a9501e3fe 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/endpoint/service/response_actions/type_guards.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/endpoint/service/response_actions/type_guards.ts @@ -15,6 +15,8 @@ import type { ResponseActionUploadOutputContent, ResponseActionUploadParameters, GetProcessesActionOutputContent, + ResponseActionRunScriptOutputContent, + ResponseActionRunScriptParameters, } from '../../types'; import { RESPONSE_ACTION_AGENT_TYPE, RESPONSE_ACTION_TYPE } from './constants'; @@ -47,6 +49,15 @@ export const isProcessesAction = ( return action.command === 'running-processes'; }; +export const isRunScriptAction = ( + action: MaybeImmutable +): action is ActionDetails< + ResponseActionRunScriptOutputContent, + ResponseActionRunScriptParameters +> => { + return action.command === 'runscript'; +}; + // type guards to ensure only the matching string values are attached to the types filter type export const isAgentType = (type: string): type is (typeof RESPONSE_ACTION_AGENT_TYPE)[number] => RESPONSE_ACTION_AGENT_TYPE.includes(type as (typeof RESPONSE_ACTION_AGENT_TYPE)[number]); diff --git a/x-pack/solutions/security/plugins/security_solution/common/endpoint/types/actions.ts b/x-pack/solutions/security/plugins/security_solution/common/endpoint/types/actions.ts index 131a8d0c6df5c..e3c47102ce719 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/endpoint/types/actions.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/endpoint/types/actions.ts @@ -97,7 +97,8 @@ export interface ResponseActionScanOutputContent { } export interface ResponseActionRunScriptOutputContent { - output: string; + stdout: string; + stderr: string; code: string; } diff --git a/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts b/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts index 428a48cf4b7be..56f4657500c45 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts @@ -109,11 +109,6 @@ export const allowedExperimentalValues = Object.freeze({ */ securitySolutionNotesDisabled: false, - /** - * Disables entity and alert previews - */ - entityAlertPreviewDisabled: false, - /** * Enables the Assistant Model Evaluation advanced setting and API endpoint, introduced in `8.11.0`. */ @@ -266,8 +261,12 @@ export const allowedExperimentalValues = Object.freeze({ /** * Enables CrowdStrike's RunScript RTR command */ - crowdstrikeRunScriptEnabled: false, + + /** + * Enables the Asset Inventory feature + */ + assetInventoryStoreEnabled: false, }); type ExperimentalConfigKeys = Array; diff --git a/x-pack/solutions/security/plugins/security_solution/docs/openapi/README.md b/x-pack/solutions/security/plugins/security_solution/docs/openapi/README.md index 4c3b55c8ab23d..3cbe1c1f42336 100644 --- a/x-pack/solutions/security/plugins/security_solution/docs/openapi/README.md +++ b/x-pack/solutions/security/plugins/security_solution/docs/openapi/README.md @@ -32,8 +32,8 @@ Security Solution has multiple API domains scattered across Kibana. Currently th - Security Endpoint Exceptions - - Bundling script: `packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js` - - Bundles location: `packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/{ess|serverless}` + - Bundling script: `x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js` + - Bundles location: `x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/{ess|serverless}` - Security Endpoint Management @@ -47,13 +47,13 @@ Security Solution has multiple API domains scattered across Kibana. Currently th - Security Security Exceptions - - Bundling script: `packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js` - - Bundles location: `packages/kbn-securitysolution-exceptions-common/docs/openapi/{ess|serverless}` + - Bundling script: `x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js` + - Bundles location: `x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common/docs/openapi/{ess|serverless}` - Security Lists - - Bundling script: `packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js` - - Bundles location: `packages/kbn-securitysolution-lists-common/docs/openapi/{ess|serverless}` + - Bundling script: `x-pack/solutions/security/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js` + - Bundles location: `x-pack/solutions/security/packages/kbn-securitysolution-lists-common/docs/openapi/{ess|serverless}` - Security Osquery diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts b/x-pack/solutions/security/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts index f4c61c1e7bf7b..1666a2e65f9cd 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts @@ -9,9 +9,10 @@ import type { CellValueContext, IEmbeddable } from '@kbn/embeddable-plugin/publi import { isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; import { createAction } from '@kbn/ui-actions-plugin/public'; import copy from 'copy-to-clipboard'; +import { isLensApi } from '@kbn/lens-plugin/public'; import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import { KibanaServices } from '../../../../common/lib/kibana'; -import { fieldHasCellActions, isCountField, isLensEmbeddable } from '../../utils'; +import { fieldHasCellActions, isCountField } from '../../utils'; import { COPY_TO_CLIPBOARD, COPY_TO_CLIPBOARD_ICON, COPY_TO_CLIPBOARD_SUCCESS } from '../constants'; export const ACTION_ID = 'embeddable_copyToClipboard'; @@ -39,7 +40,7 @@ export const createCopyToClipboardLensAction = ({ order }: { order?: number }) = getDisplayName: () => COPY_TO_CLIPBOARD, isCompatible: async ({ embeddable, data }) => !isErrorEmbeddable(embeddable as IEmbeddable) && - isLensEmbeddable(embeddable as IEmbeddable) && + isLensApi(embeddable) && isDataColumnsValid(data) && isInSecurityApp(currentAppId), execute: async ({ data }) => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/actions/filter/lens/create_action.ts b/x-pack/solutions/security/plugins/security_solution/public/app/actions/filter/lens/create_action.ts index e264466767287..79bcd0e87ced5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/actions/filter/lens/create_action.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/app/actions/filter/lens/create_action.ts @@ -16,9 +16,10 @@ import type { CellValueContext, IEmbeddable } from '@kbn/embeddable-plugin/publi import { createAction } from '@kbn/ui-actions-plugin/public'; import { ACTION_INCOMPATIBLE_VALUE_WARNING } from '@kbn/cell-actions/src/actions/translations'; import { i18n } from '@kbn/i18n'; +import { isLensApi } from '@kbn/lens-plugin/public'; import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import { timelineSelectors } from '../../../../timelines/store'; -import { fieldHasCellActions, isLensEmbeddable } from '../../utils'; +import { fieldHasCellActions } from '../../utils'; import { TimelineId } from '../../../../../common/types'; import { DefaultCellActionTypes } from '../../constants'; import type { SecurityAppStore } from '../../../../common/store'; @@ -79,7 +80,7 @@ export const createFilterLensAction = ({ type: DefaultCellActionTypes.FILTER, isCompatible: async ({ embeddable, data }) => !isErrorEmbeddable(embeddable as IEmbeddable) && - isLensEmbeddable(embeddable as IEmbeddable) && + isLensApi(embeddable) && isDataColumnsValid(data) && isInSecurityApp(currentAppId), execute: async ({ data }) => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/actions/utils.ts b/x-pack/solutions/security/plugins/security_solution/public/app/actions/utils.ts index 3da597db60c0e..568a5f10f31ec 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/actions/utils.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/app/actions/utils.ts @@ -4,8 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { IEmbeddable } from '@kbn/embeddable-plugin/public'; -import { isLensApi } from '@kbn/lens-plugin/public'; import type { Serializable } from '@kbn/utility-types'; // All cell actions are disabled for these fields in Security @@ -16,12 +14,6 @@ const FIELDS_WITHOUT_CELL_ACTIONS = [ 'kibana.alert.reason', ]; -// @TODO: this is a temporary fix. It needs a better refactor on the consumer side here to -// adapt to the new Embeddable architecture -export const isLensEmbeddable = (embeddable: IEmbeddable): embeddable is IEmbeddable => { - return isLensApi(embeddable); -}; - export const fieldHasCellActions = (field?: string): boolean => { return !!field && !FIELDS_WITHOUT_CELL_ACTIONS.includes(field); }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx index 3e08f4ce3acc8..177ff4e18d426 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { isEmpty } from 'lodash/fp'; import { EuiDescriptionList, @@ -23,8 +23,8 @@ import type { import type { Filter } from '@kbn/es-query'; import type { SavedQuery } from '@kbn/data-plugin/public'; import { mapAndFlattenFilters } from '@kbn/data-plugin/public'; -import type { DataView } from '@kbn/data-views-plugin/public'; import { FilterItems } from '@kbn/unified-search-plugin/public'; +import { isDataView } from '../../../../common/components/query_bar'; import type { AlertSuppressionMissingFieldsStrategy, EqlOptionalFields, @@ -40,8 +40,6 @@ import { AlertSuppressionLabel } from '../../../rule_creation_ui/components/desc import { useGetSavedQuery } from '../../../../detections/pages/detection_engine/rules/use_get_saved_query'; import * as threatMatchI18n from '../../../../common/components/threat_match/translations'; import * as timelinesI18n from '../../../../timelines/components/timeline/translations'; -import { useRuleIndexPattern } from '../../../rule_creation_ui/pages/form'; -import { DataSourceType } from '../../../../detections/pages/detection_engine/rules/types'; import type { Duration } from '../../../../detections/pages/detection_engine/rules/types'; import { convertHistoryStartToSize } from '../../../../detections/pages/detection_engine/rules/helpers'; import { MlJobsDescription } from '../../../rule_creation/components/ml_jobs_description/ml_jobs_description'; @@ -65,6 +63,7 @@ import { EQL_OPTIONS_EVENT_TIEBREAKER_FIELD_LABEL, EQL_OPTIONS_EVENT_TIMESTAMP_FIELD_LABEL, } from '../../../rule_creation/components/eql_query_edit/translations'; +import { useDataView } from './three_way_diff/final_edit/fields/hooks/use_data_view'; interface SavedQueryNameProps { savedQueryName: string; @@ -89,16 +88,34 @@ export const Filters = ({ index, 'data-test-subj': dataTestSubj, }: FiltersProps) => { - const flattenedFilters = mapAndFlattenFilters(filters); - const defaultIndexPattern = useDefaultIndexPattern(); + const useDataViewParams = dataViewId + ? { dataViewId } + : { indexPatterns: index ?? defaultIndexPattern }; + const { dataView } = useDataView(useDataViewParams); + const isEsql = filters.some((filter) => filter?.query?.language === 'esql'); + const searchBarFilters = useMemo(() => { + if (!index || isDataView(index) || isEsql) { + return filters; + } + const filtersWithUpdatedMetaIndex = filters.map((filter) => { + return { + ...filter, + meta: { + ...filter.meta, + index: index.join(','), + }, + }; + }); - const { indexPattern } = useRuleIndexPattern({ - dataSourceType: dataViewId ? DataSourceType.DataView : DataSourceType.IndexPatterns, - index: index ?? defaultIndexPattern, - dataViewId, - }); + return filtersWithUpdatedMetaIndex; + }, [filters, index, isEsql]); + + if (!dataView) { + return null; + } + const flattenedFilters = mapAndFlattenFilters(searchBarFilters); const styles = filtersStyles; return ( @@ -109,7 +126,7 @@ export const Filters = ({ responsive={false} gutterSize="xs" > - + ); }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx index 37b23652bfcbe..1f4e6a255fb86 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx @@ -57,7 +57,7 @@ export function ComparisonSideHelpInfo({ options }: ComparisonSideHelpInfoProps)
    {optionsWithDescriptions.map( ({ title: displayName, description: explanation }) => ( -
  • +
  • {displayName} {'-'} {explanation}
  • ) diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/hooks/use_data_view.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/hooks/use_data_view.ts index 4cfb307665308..123a7b3cffb58 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/hooks/use_data_view.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/hooks/use_data_view.ts @@ -9,7 +9,7 @@ import { useEffect, useState } from 'react'; import type { DataView } from '@kbn/data-views-plugin/common'; import { useKibana } from '../../../../../../../../common/lib/kibana'; -type UseDataViewParams = +export type UseDataViewParams = | { indexPatterns: string[]; dataViewId?: never } | { indexPatterns?: never; dataViewId: string }; @@ -33,6 +33,7 @@ export function useDataView(indexPatternsOrDataViewId: UseDataViewParams): UseDa if (indexPatternsOrDataViewId.indexPatterns) { const indexPatternsDataView = await dataViewsService.create({ title: indexPatternsOrDataViewId.indexPatterns.join(','), + id: indexPatternsOrDataViewId.indexPatterns.join(','), allowNoIndex: true, }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx index 7354bd306d6ea..f1f79e911ec4f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx @@ -64,11 +64,11 @@ describe('Component BulkEditRuleErrorsList', () => { ], [ BulkActionsDryRunErrCode.MACHINE_LEARNING_INDEX_PATTERN, - "2 custom machine learning rules (these rules don't have index patterns)", + "2 machine learning rules (these rules don't have index patterns)", ], [ BulkActionsDryRunErrCode.ESQL_INDEX_PATTERN, - "2 custom ES|QL rules (these rules don't have index patterns)", + "2 ES|QL rules (these rules don't have index patterns)", ], [ BulkActionsDryRunErrCode.MACHINE_LEARNING_AUTH, diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx index 72e380a1a7d5a..ce6be3edbf14c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx @@ -41,7 +41,7 @@ const BulkEditRuleErrorItem = ({
  • @@ -61,7 +61,7 @@ const BulkEditRuleErrorItem = ({
  • diff --git a/x-pack/solutions/security/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index cb0570855dabe..b12355c109879 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -265,13 +265,13 @@ export const BULK_EDIT_CONFIRMATION_REJECTED_TITLE = (rulesCount: number) => } ); -export const BULK_ACTION_CONFIRMATION_PARTLY_TITLE = (customRulesCount: number) => +export const BULK_ACTION_CONFIRMATION_PARTLY_TITLE = (rulesCount: number) => i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkActionConfirmationPartlyTitle', { - values: { customRulesCount }, + values: { rulesCount }, defaultMessage: - 'This action can only be applied to {customRulesCount, plural, =1 {# custom rule} other {# custom rules}}', + 'This action can only be applied to {rulesCount, plural, =1 {# rule} other {# rules}}', } ); @@ -289,32 +289,30 @@ export const BULK_ACTION_CONFIRMATION_CLOSE = i18n.translate( } ); -export const BULK_EDIT_CONFIRMATION_CONFIRM = (customRulesCount: number) => +export const BULK_EDIT_CONFIRMATION_CONFIRM = (rulesCount: number) => i18n.translate( 'xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel', { - values: { customRulesCount }, - defaultMessage: 'Edit {customRulesCount, plural, =1 {# custom rule} other {# custom rules}}', + values: { rulesCount }, + defaultMessage: 'Edit {rulesCount, plural, =1 {# rule} other {# rules}}', } ); -export const BULK_EXPORT_CONFIRMATION_CONFIRM = (customRulesCount: number) => +export const BULK_EXPORT_CONFIRMATION_CONFIRM = (rulesCount: number) => i18n.translate( 'xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkExportConfirmation.confirmButtonLabel', { - values: { customRulesCount }, - defaultMessage: - 'Export {customRulesCount, plural, =1 {# custom rule} other {# custom rules}}', + values: { rulesCount }, + defaultMessage: 'Export {rulesCount, plural, =1 {# rule} other {# rules}}', } ); -export const BULK_MANUAL_RULE_RUN_CONFIRMATION_CONFIRM = (customRulesCount: number) => +export const BULK_MANUAL_RULE_RUN_CONFIRMATION_CONFIRM = (rulesCount: number) => i18n.translate( 'xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkManualRuleRunConfirmation.confirmButtonLabel', { - values: { customRulesCount }, - defaultMessage: - 'Schedule {customRulesCount, plural, =1 {# custom rule} other {# custom rules}}', + values: { rulesCount }, + defaultMessage: 'Schedule {rulesCount, plural, =1 {# rule} other {# rules}}', } ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs.test.tsx index 6995656db31a5..7ff2a6feb958f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs.test.tsx @@ -49,12 +49,6 @@ const riskScore = { }, }; -const mockUseIsExperimentalFeatureEnabled = jest.fn().mockReturnValue(false); - -jest.mock('../../../../../common/hooks/use_experimental_features', () => ({ - useIsExperimentalFeatureEnabled: () => mockUseIsExperimentalFeatureEnabled(), -})); - const riskScoreWithAssetCriticalityContribution = (contribution: number) => { const score = JSON.parse(JSON.stringify(riskScore)); score.user.risk.category_2_score = contribution; @@ -129,8 +123,7 @@ describe('RiskInputsTab', () => { expect(queryByTestId('risk-input-contexts-title')).toBeInTheDocument(); }); - it('it renders alert preview button when feature flag is enable', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('it renders alert preview button', () => { mockUseRiskScore.mockReturnValue({ loading: false, error: false, @@ -151,28 +144,6 @@ describe('RiskInputsTab', () => { expect(getByTestId(EXPAND_ALERT_TEST_ID)).toBeInTheDocument(); }); - it('it does not render alert preview button when feature flag is disable', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); - mockUseRiskScore.mockReturnValue({ - loading: false, - error: false, - data: [riskScore], - }); - mockUseRiskContributingAlerts.mockReturnValue({ - loading: false, - error: false, - data: [alertInputDataMock], - }); - - const { queryByTestId } = render( - - - - ); - - expect(queryByTestId(EXPAND_ALERT_TEST_ID)).not.toBeInTheDocument(); - }); - it('Displays 0.00 for the asset criticality contribution if the contribution value is less than -0.01', () => { mockUseUiSetting.mockReturnValue([true]); diff --git a/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs_tab.tsx b/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs_tab.tsx index 78010434ee593..72a6af0fe768f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs_tab.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs_tab.tsx @@ -14,7 +14,6 @@ import { ALERT_RULE_NAME } from '@kbn/rule-data-utils'; import { get } from 'lodash/fp'; import { AlertPreviewButton } from '../../../../../flyout/shared/components/alert_preview_button'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { useGlobalTime } from '../../../../../common/containers/use_global_time'; import { useQueryInspector } from '../../../../../common/components/page/manage_query'; import { formatRiskScore } from '../../../../common'; @@ -98,26 +97,20 @@ export const RiskInputsTab = ({ entityType, entityName, scopeId }: RiskInputsTab }), [] ); - const isPreviewEnabled = !useIsExperimentalFeatureEnabled('entityAlertPreviewDisabled'); const inputColumns: Array> = useMemo( () => [ - ...(isPreviewEnabled - ? [ - { - render: (data: InputAlert) => ( - - ), - width: '5%', - }, - ] - : []), - + { + render: (data: InputAlert) => ( + + ), + width: '5%', + }, { name: ( describe('CorrelationsDetailsAlertsTable', () => { beforeEach(() => { jest.mocked(useExpandableFlyoutApi).mockReturnValue(mockFlyoutApi); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); jest.mocked(usePaginatedAlerts).mockReturnValue({ setPagination: jest.fn(), setSorting: jest.fn(), @@ -88,16 +84,16 @@ describe('CorrelationsDetailsAlertsTable', () => { }); it('renders EuiBasicTable with correct props', () => { - const { getByTestId, queryByTestId, queryAllByRole } = + const { getByTestId, getAllByTestId, queryAllByRole } = renderCorrelationsTable(mockContextValue); expect(getByTestId(`${TEST_ID}InvestigateInTimeline`)).toBeInTheDocument(); expect(getByTestId(`${TEST_ID}Table`)).toBeInTheDocument(); - expect(queryByTestId(`${TEST_ID}AlertPreviewButton`)).not.toBeInTheDocument(); + expect(getAllByTestId(`${TEST_ID}AlertPreviewButton`)).toHaveLength(2); expect(jest.mocked(usePaginatedAlerts)).toHaveBeenCalled(); - expect(queryAllByRole('columnheader').length).toBe(4); + expect(queryAllByRole('columnheader').length).toBe(5); expect(queryAllByRole('row').length).toBe(3); // 1 header row and 2 data rows expect(queryAllByRole('row')[1].textContent).toContain('Jan 1, 2022 @ 00:00:00.000'); expect(queryAllByRole('row')[1].textContent).toContain('Reason1'); @@ -105,8 +101,7 @@ describe('CorrelationsDetailsAlertsTable', () => { expect(queryAllByRole('row')[1].textContent).toContain('Severity1'); }); - it('renders open preview button when feature flag is on', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('renders open preview button', () => { const { getByTestId, getAllByTestId } = renderCorrelationsTable({ ...mockContextValue, isPreviewMode: true, @@ -128,8 +123,7 @@ describe('CorrelationsDetailsAlertsTable', () => { }); }); - it('opens rule preview when feature flag is on and isPreview is false', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('opens rule preview when isPreview is false', () => { const { getAllByTestId } = renderCorrelationsTable(mockContextValue); expect(getAllByTestId(`${TEST_ID}RulePreview`).length).toBe(2); @@ -145,8 +139,7 @@ describe('CorrelationsDetailsAlertsTable', () => { }); }); - it('does not render preview link when feature flag is on and isPreview is true', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('does not render preview link when isPreview is true', () => { const { queryByTestId } = renderCorrelationsTable({ ...mockContextValue, isPreview: true }); expect(queryByTestId(`${TEST_ID}RulePreview`)).not.toBeInTheDocument(); }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx index d8497ca984ea8..4d757b46edb27 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx @@ -14,7 +14,6 @@ import { isRight } from 'fp-ts/lib/Either'; import { ALERT_REASON, ALERT_RULE_NAME } from '@kbn/rule-data-utils'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { CellTooltipWrapper } from '../../shared/components/cell_tooltip_wrapper'; import type { DataProvider } from '../../../../../common/types'; import { SeverityBadge } from '../../../../common/components/severity_badge'; @@ -82,8 +81,6 @@ export const CorrelationsDetailsAlertsTable: FC [ - ...(isPreviewEnabled - ? [ - { - render: (row: Record) => ( - - ), - width: '5%', - }, - ] - : []), + { + render: (row: Record) => ( + + ), + width: '5%', + }, { field: '@timestamp', name: ( @@ -176,20 +169,16 @@ export const CorrelationsDetailsAlertsTable: FC - {isPreviewEnabled ? ( - - {ruleName} - - ) : ( + {ruleName} - )} + ); }, @@ -229,7 +218,7 @@ export const CorrelationsDetailsAlertsTable: FC { const dataView = useGetScopedSourcererDataView({ sourcererScope: SourcererScopeName.default, }); - const { getFieldsData, dataAsNestedObject } = useDocumentDetailsContext(); - const { eventIds, timestamp } = useGraphPreview({ + const { getFieldsData, dataAsNestedObject, dataFormattedForFieldBrowser } = + useDocumentDetailsContext(); + const { + eventIds, + timestamp = new Date().toISOString(), + isAlert, + } = useGraphPreview({ getFieldsData, ecsData: dataAsNestedObject, + dataFormattedForFieldBrowser, }); + const originEventIds = eventIds.map((id) => ({ id, isAlert })); + return (
    { > {dataView && ( }> - + )}
    diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx index e08a794665222..86d04a9c94a77 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx @@ -17,7 +17,6 @@ import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml import { mockAnomalies } from '../../../../common/components/ml/mock'; import { useHostDetails } from '../../../../explore/hosts/containers/hosts/details'; import { useHostRelatedUsers } from '../../../../common/containers/related_entities/related_users'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { RiskSeverity } from '../../../../../common/search_strategy'; import { HOST_DETAILS_TEST_ID, @@ -46,9 +45,6 @@ jest.mock('@kbn/expandable-flyout'); jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'); jest.mock('@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'); -jest.mock('../../../../common/hooks/use_experimental_features'); -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; - jest.mock('react-router-dom', () => { const actual = jest.requireActual('react-router-dom'); return { ...actual, useLocation: jest.fn().mockReturnValue({ pathname: '' }) }; @@ -180,20 +176,18 @@ describe('', () => { mockUseHostDetails.mockReturnValue(mockHostDetailsResponse); mockUseRiskScore.mockReturnValue(mockRiskScoreResponse); mockUseHostsRelatedUsers.mockReturnValue(mockRelatedUsersResponse); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); (useMisconfigurationPreview as jest.Mock).mockReturnValue({}); (useVulnerabilitiesPreview as jest.Mock).mockReturnValue({}); (useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: false, items: {} }); }); it('should render host details correctly', () => { - const { getByTestId, queryByTestId } = renderHostDetails(mockContextValue); + const { getByTestId } = renderHostDetails(mockContextValue); expect(getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(HOST_DETAILS_TEST_ID))).toBeInTheDocument(); - expect(queryByTestId(HOST_DETAILS_LINK_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(HOST_DETAILS_LINK_TEST_ID)).toBeInTheDocument(); }); - it('should render host name as clicable link when preview is not disabled', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('should render host name as clicable link', () => { const { getByTestId } = renderHostDetails(mockContextValue); expect(getByTestId(HOST_DETAILS_LINK_TEST_ID)).toBeInTheDocument(); @@ -242,7 +236,7 @@ describe('', () => { describe('Related users', () => { it('should render the related user table with correct dates and indices', () => { - const { getByTestId, queryByTestId } = renderHostDetails(mockContextValue); + const { getByTestId } = renderHostDetails(mockContextValue); expect(mockUseHostsRelatedUsers).toBeCalledWith({ from: timestamp, hostName: 'test host', @@ -250,7 +244,7 @@ describe('', () => { skip: false, }); expect(getByTestId(HOST_DETAILS_RELATED_USERS_TABLE_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(HOST_DETAILS_RELATED_USERS_LINK_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(HOST_DETAILS_RELATED_USERS_LINK_TEST_ID)).toBeInTheDocument(); }); it('should render user risk score column when license and capabilities are valid', () => { @@ -296,8 +290,7 @@ describe('', () => { ); }); - it('should render user name as clicable link when preview is not disabled', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('should render user name as clicable link', () => { const { getAllByTestId } = renderHostDetails(mockContextValue); expect(getAllByTestId(HOST_DETAILS_RELATED_USERS_LINK_TEST_ID).length).toBe(1); diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx index e3fd2fef8bc6e..9555860a329b3 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx @@ -25,14 +25,12 @@ import type { EuiBasicTableColumn } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { ExpandablePanel } from '../../../shared/components/expandable_panel'; import type { RelatedUser } from '../../../../../common/search_strategy/security_solution/related_entities/related_users'; import type { RiskSeverity } from '../../../../../common/search_strategy'; import { HostOverview } from '../../../../overview/components/host_overview'; import { AnomalyTableProvider } from '../../../../common/components/ml/anomaly/anomaly_table_provider'; import { InspectButton, InspectButtonContainer } from '../../../../common/components/inspect'; -import { NetworkDetailsLink } from '../../../../common/components/links'; import { RiskScoreEntity } from '../../../../../common/search_strategy'; import { RiskScoreLevel } from '../../../../entity_analytics/components/severity/common'; import { DefaultFieldRenderer } from '../../../../timelines/components/field_renderers/default_renderer'; @@ -110,7 +108,6 @@ export const HostDetails: React.FC = ({ hostName, timestamp, s const isEntityAnalyticsAuthorized = isPlatinumOrTrialLicense && hasEntityAnalyticsCapability; const { openPreviewPanel } = useExpandableFlyoutApi(); - const isPreviewEnabled = !useIsExperimentalFeatureEnabled('entityAlertPreviewDisabled'); const narrowDateRange = useCallback( (score, interval) => { @@ -176,16 +173,12 @@ export const HostDetails: React.FC = ({ hostName, timestamp, s render: (user: string) => ( - {isPreviewEnabled ? ( - - ) : ( - <>{user} - )} + ), @@ -208,15 +201,13 @@ export const HostDetails: React.FC = ({ hostName, timestamp, s render={(ip) => ip == null ? ( getEmptyTagValue() - ) : isPreviewEnabled ? ( + ) : ( - ) : ( - ) } scopeId={scopeId} @@ -242,7 +233,7 @@ export const HostDetails: React.FC = ({ hostName, timestamp, s ] : []), ], - [isEntityAnalyticsAuthorized, scopeId, isPreviewEnabled] + [isEntityAnalyticsAuthorized, scopeId] ); const relatedUsersCount = useMemo( @@ -273,19 +264,14 @@ export const HostDetails: React.FC = ({ hostName, timestamp, s }; const hostLink = useMemo( - () => - isPreviewEnabled - ? { - callback: openHostPreview, - tooltip: i18n.translate( - 'xpack.securitySolution.flyout.left.insights.entities.host.hostPreviewTitle', - { - defaultMessage: 'Preview host', - } - ), - } - : undefined, - [isPreviewEnabled, openHostPreview] + () => ({ + callback: openHostPreview, + tooltip: i18n.translate( + 'xpack.securitySolution.flyout.left.insights.entities.host.hostPreviewTitle', + { defaultMessage: 'Preview host' } + ), + }), + [openHostPreview] ); return ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.test.tsx index e8b1b71e9cd0f..e0bef746b213b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.test.tsx @@ -24,7 +24,6 @@ import { import { usePrevalence } from '../../shared/hooks/use_prevalence'; import { TestProviders } from '../../../../common/mock'; import { licenseService } from '../../../../common/hooks/use_license'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { mockFlyoutApi } from '../../shared/mocks/mock_flyout_context'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { HostPreviewPanelKey } from '../../../entity_details/host_right'; @@ -46,9 +45,6 @@ jest.mock('../../../../common/lib/kibana', () => { }; }); -jest.mock('../../../../common/hooks/use_experimental_features'); -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; - jest.mock('../../shared/hooks/use_prevalence'); const mockDispatch = jest.fn(); @@ -138,7 +134,6 @@ describe('PrevalenceDetails', () => { jest.clearAllMocks(); licenseServiceMock.isPlatinumPlus.mockReturnValue(true); jest.mocked(useExpandableFlyoutApi).mockReturnValue(mockFlyoutApi); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); }); it('should render the table with all data if license is platinum', () => { @@ -162,13 +157,10 @@ describe('PrevalenceDetails', () => { ).toBeGreaterThan(1); expect(queryByTestId(PREVALENCE_DETAILS_UPSELL_TEST_ID)).not.toBeInTheDocument(); expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); - expect( - queryByTestId(PREVALENCE_DETAILS_TABLE_PREVIEW_LINK_CELL_TEST_ID) - ).not.toBeInTheDocument(); + expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_PREVIEW_LINK_CELL_TEST_ID)).toHaveLength(2); }); - it('should render host and user name as clickable link if preview is enabled', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('should render host and user name as clickable link', () => { (usePrevalence as jest.Mock).mockReturnValue(mockPrevelanceReturnValue); const { getAllByTestId } = renderPrevalenceDetails(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.tsx index 6491bc9ad2747..77ab6eb66df31 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.tsx @@ -22,7 +22,6 @@ import { useEuiTheme, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { FormattedCount } from '../../../../common/components/formatted_number'; import { useLicense } from '../../../../common/hooks/use_license'; import { InvestigateInTimelineButton } from '../../../../common/components/event_details/investigate_in_timeline_button'; @@ -81,10 +80,6 @@ interface PrevalenceDetailsRow extends PrevalenceData { * License to drive the rendering of the last 2 prevalence columns */ isPlatinumPlus: boolean; - /** - * If enabled, clicking host or user should open an entity preview - */ - isPreviewEnabled: boolean; /** * Scope id to pass to the preview link */ @@ -115,7 +110,7 @@ const columns: Array> = [ render: (data: PrevalenceDetailsRow) => ( {data.values.map((value) => { - if (data.isPreviewEnabled && hasPreview(data.field)) { + if (hasPreview(data.field)) { return ( @@ -331,7 +326,6 @@ export const PrevalenceDetails: React.FC = () => { useDocumentDetailsContext(); const isPlatinumPlus = useLicense().isPlatinumPlus(); - const isPreviewEnabled = !useIsExperimentalFeatureEnabled('entityAlertPreviewDisabled'); // these two are used by the usePrevalence hook to fetch the data const [start, setStart] = useState(DEFAULT_FROM); @@ -382,10 +376,9 @@ export const PrevalenceDetails: React.FC = () => { from: absoluteStart, to: absoluteEnd, isPlatinumPlus, - isPreviewEnabled, scopeId, })), - [data, absoluteStart, absoluteEnd, isPlatinumPlus, isPreviewEnabled, scopeId] + [data, absoluteStart, absoluteEnd, isPlatinumPlus, scopeId] ); const upsell = ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx index 5bfb8a7df50db..993e9101ba0f0 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx @@ -16,7 +16,6 @@ import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml import { mockAnomalies } from '../../../../common/components/ml/mock'; import { useObservedUserDetails } from '../../../../explore/users/containers/users/observed_details'; import { useUserRelatedHosts } from '../../../../common/containers/related_entities/related_hosts'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { RiskSeverity } from '../../../../../common/search_strategy'; import { USER_DETAILS_TEST_ID, @@ -43,9 +42,6 @@ import { useAlertsByStatus } from '../../../../overview/components/detection_res jest.mock('@kbn/expandable-flyout'); jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'); -jest.mock('../../../../common/hooks/use_experimental_features'); -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; - jest.mock('react-router-dom', () => { const actual = jest.requireActual('react-router-dom'); return { ...actual, useLocation: jest.fn().mockReturnValue({ pathname: '' }) }; @@ -174,19 +170,17 @@ describe('', () => { mockUseObservedUserDetails.mockReturnValue(mockUserDetailsResponse); mockUseRiskScore.mockReturnValue(mockRiskScoreResponse); mockUseUsersRelatedHosts.mockReturnValue(mockRelatedHostsResponse); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); (useMisconfigurationPreview as jest.Mock).mockReturnValue({}); (useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: false, items: {} }); }); it('should render user details correctly', () => { - const { getByTestId, queryByTestId } = renderUserDetails(mockContextValue); + const { getByTestId } = renderUserDetails(mockContextValue); expect(getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(USER_DETAILS_TEST_ID))).toBeInTheDocument(); - expect(queryByTestId(USER_DETAILS_LINK_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(USER_DETAILS_LINK_TEST_ID)).toBeInTheDocument(); }); - it('should render user name as clicable link when feature flag is true', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('should render user name as clicable link', () => { const { getByTestId } = renderUserDetails(mockContextValue); expect(getByTestId(USER_DETAILS_LINK_TEST_ID)).toBeInTheDocument(); @@ -233,7 +227,7 @@ describe('', () => { describe('Related hosts', () => { it('should render the related host table with correct dates and indices', () => { - const { getByTestId, queryByTestId } = renderUserDetails(mockContextValue); + const { getByTestId } = renderUserDetails(mockContextValue); expect(mockUseUsersRelatedHosts).toBeCalledWith({ from: timestamp, userName: 'test user', @@ -241,7 +235,7 @@ describe('', () => { skip: false, }); expect(getByTestId(USER_DETAILS_RELATED_HOSTS_TABLE_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(USER_DETAILS_RELATED_HOSTS_LINK_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(USER_DETAILS_RELATED_HOSTS_LINK_TEST_ID)).toBeInTheDocument(); }); it('should render host risk score column when license is valid', () => { @@ -274,8 +268,7 @@ describe('', () => { ); }); - it('should render host name and ip as clicable link when preview is enabled', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('should render host name and ip as clicable link', () => { const { getAllByTestId } = renderUserDetails(mockContextValue); expect(getAllByTestId(USER_DETAILS_RELATED_HOSTS_LINK_TEST_ID).length).toBe(1); diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx index e88cbb54f9471..00366a367a81f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx @@ -25,14 +25,12 @@ import type { EuiBasicTableColumn } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { ExpandablePanel } from '../../../shared/components/expandable_panel'; import type { RelatedHost } from '../../../../../common/search_strategy/security_solution/related_entities/related_hosts'; import type { RiskSeverity } from '../../../../../common/search_strategy'; import { UserOverview } from '../../../../overview/components/user_overview'; import { AnomalyTableProvider } from '../../../../common/components/ml/anomaly/anomaly_table_provider'; import { InspectButton, InspectButtonContainer } from '../../../../common/components/inspect'; -import { NetworkDetailsLink } from '../../../../common/components/links'; import { RiskScoreEntity } from '../../../../../common/search_strategy'; import { RiskScoreLevel } from '../../../../entity_analytics/components/severity/common'; import { DefaultFieldRenderer } from '../../../../timelines/components/field_renderers/default_renderer'; @@ -109,7 +107,6 @@ export const UserDetails: React.FC = ({ userName, timestamp, s const isEntityAnalyticsAuthorized = isPlatinumOrTrialLicense && hasEntityAnalyticsCapability; const { openPreviewPanel } = useExpandableFlyoutApi(); - const isPreviewEnabled = !useIsExperimentalFeatureEnabled('entityAlertPreviewDisabled'); const narrowDateRange = useCallback( (score, interval) => { @@ -175,16 +172,12 @@ export const UserDetails: React.FC = ({ userName, timestamp, s render: (host: string) => ( - {isPreviewEnabled ? ( - - ) : ( - <>{host} - )} + ), @@ -207,15 +200,13 @@ export const UserDetails: React.FC = ({ userName, timestamp, s render={(ip) => ip == null ? ( getEmptyTagValue() - ) : isPreviewEnabled ? ( + ) : ( - ) : ( - ) } scopeId={scopeId} @@ -241,7 +232,7 @@ export const UserDetails: React.FC = ({ userName, timestamp, s ] : []), ], - [isEntityAnalyticsAuthorized, scopeId, isPreviewEnabled] + [isEntityAnalyticsAuthorized, scopeId] ); const relatedHostsCount = useMemo( @@ -272,19 +263,14 @@ export const UserDetails: React.FC = ({ userName, timestamp, s }; const userLink = useMemo( - () => - isPreviewEnabled - ? { - callback: openUserPreview, - tooltip: i18n.translate( - 'xpack.securitySolution.flyout.left.insights.entities.user.userPreviewTitle', - { - defaultMessage: 'Preview user', - } - ), - } - : undefined, - [isPreviewEnabled, openUserPreview] + () => ({ + callback: openUserPreview, + tooltip: i18n.translate( + 'xpack.securitySolution.flyout.left.insights.entities.user.userPreviewTitle', + { defaultMessage: 'Preview user' } + ), + }), + [openUserPreview] ); return ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/tabs/visualize_tab.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/tabs/visualize_tab.tsx index 89e00e06e3a49..1a8e5906e247e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/tabs/visualize_tab.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/tabs/visualize_tab.tsx @@ -88,7 +88,8 @@ const graphVisualizationButton: EuiButtonGroupOptionProps = { * Visualize view displayed in the document details expandable flyout left section */ export const VisualizeTab = memo(() => { - const { scopeId, getFieldsData, dataAsNestedObject } = useDocumentDetailsContext(); + const { scopeId, getFieldsData, dataAsNestedObject, dataFormattedForFieldBrowser } = + useDocumentDetailsContext(); const { openPreviewPanel } = useExpandableFlyoutApi(); const panels = useExpandableFlyoutState(); const [activeVisualizationId, setActiveVisualizationId] = useState( @@ -123,6 +124,7 @@ export const VisualizeTab = memo(() => { const { hasGraphRepresentation } = useGraphPreview({ getFieldsData, ecsData: dataAsNestedObject, + dataFormattedForFieldBrowser, }); const isGraphFeatureEnabled = useIsExperimentalFeatureEnabled( diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.test.tsx index c805f2a3c67a7..9965c5300e71f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.test.tsx @@ -86,6 +86,7 @@ describe('', () => { timestamp, eventIds: [], hasGraphRepresentation: true, + isAlert: true, }); const { getByTestId, queryByTestId, findByTestId } = renderGraphPreview(); @@ -111,7 +112,109 @@ describe('', () => { expect(mockUseFetchGraphData.mock.calls[0][0]).toEqual({ req: { query: { - eventIds: [], + originEventIds: [], + start: `${timestamp}||-30m`, + end: `${timestamp}||+30m`, + }, + }, + options: { + enabled: true, + refetchOnWindowFocus: false, + }, + }); + }); + + it('should render component for alert', async () => { + mockUseFetchGraphData.mockReturnValue({ + isLoading: false, + isError: false, + data: { nodes: DEFAULT_NODES, edges: [] }, + }); + + const timestamp = new Date().toISOString(); + + (useGraphPreview as jest.Mock).mockReturnValue({ + timestamp, + eventIds: ['eventId'], + isAlert: true, + hasGraphRepresentation: true, + }); + + const { getByTestId, queryByTestId, findByTestId } = renderGraphPreview(); + + // Using findByTestId to wait for the component to be rendered because it is a lazy loaded component + expect(await findByTestId(GRAPH_PREVIEW_TEST_ID)).toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).toBeInTheDocument(); + expect( + queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).not.toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).toBeInTheDocument(); + expect( + queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).not.toBeInTheDocument(); + expect(mockUseFetchGraphData).toHaveBeenCalled(); + expect(mockUseFetchGraphData.mock.calls[0][0]).toEqual({ + req: { + query: { + originEventIds: [{ id: 'eventId', isAlert: true }], + start: `${timestamp}||-30m`, + end: `${timestamp}||+30m`, + }, + }, + options: { + enabled: true, + refetchOnWindowFocus: false, + }, + }); + }); + + it('should render component for event', async () => { + mockUseFetchGraphData.mockReturnValue({ + isLoading: false, + isError: false, + data: { nodes: DEFAULT_NODES, edges: [] }, + }); + + const timestamp = new Date().toISOString(); + + (useGraphPreview as jest.Mock).mockReturnValue({ + timestamp, + eventIds: ['eventId'], + isAlert: false, + hasGraphRepresentation: true, + }); + + const { getByTestId, queryByTestId, findByTestId } = renderGraphPreview(); + + // Using findByTestId to wait for the component to be rendered because it is a lazy loaded component + expect(await findByTestId(GRAPH_PREVIEW_TEST_ID)).toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).toBeInTheDocument(); + expect( + queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).not.toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).toBeInTheDocument(); + expect( + queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(GRAPH_PREVIEW_TEST_ID)) + ).not.toBeInTheDocument(); + expect(mockUseFetchGraphData).toHaveBeenCalled(); + expect(mockUseFetchGraphData.mock.calls[0][0]).toEqual({ + req: { + query: { + originEventIds: [{ id: 'eventId', isAlert: false }], start: `${timestamp}||-30m`, end: `${timestamp}||+30m`, }, @@ -136,6 +239,7 @@ describe('', () => { timestamp, eventIds: [], hasGraphRepresentation: true, + isAlert: true, }); const { getByTestId, queryByTestId, findByTestId } = renderGraphPreview({ @@ -164,7 +268,7 @@ describe('', () => { expect(mockUseFetchGraphData.mock.calls[0][0]).toEqual({ req: { query: { - eventIds: [], + originEventIds: [], start: `${timestamp}||-30m`, end: `${timestamp}||+30m`, }, @@ -189,6 +293,7 @@ describe('', () => { timestamp, eventIds: [], hasGraphRepresentation: true, + isAlert: true, }); const { getByTestId, queryByTestId, findByTestId } = renderGraphPreview({ @@ -217,7 +322,7 @@ describe('', () => { expect(mockUseFetchGraphData.mock.calls[0][0]).toEqual({ req: { query: { - eventIds: [], + originEventIds: [], start: `${timestamp}||-30m`, end: `${timestamp}||+30m`, }, @@ -243,6 +348,7 @@ describe('', () => { timestamp, eventIds: [], hasGraphRepresentation: true, + isAlert: true, }); const { getByTestId, queryByTestId, findByTestId } = renderGraphPreview(); @@ -268,7 +374,7 @@ describe('', () => { expect(mockUseFetchGraphData.mock.calls[0][0]).toEqual({ req: { query: { - eventIds: [], + originEventIds: [], start: `${timestamp}||-30m`, end: `${timestamp}||+30m`, }, @@ -293,6 +399,7 @@ describe('', () => { timestamp, eventIds: [], hasGraphRepresentation: false, + isAlert: true, }); const { getByTestId, queryByTestId, findByTestId } = renderGraphPreview(); @@ -320,7 +427,7 @@ describe('', () => { expect(mockUseFetchGraphData.mock.calls[0][0]).toEqual({ req: { query: { - eventIds: [], + originEventIds: [], start: `${timestamp}||-30m`, end: `${timestamp}||+30m`, }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.tsx index 90a0218778549..b4626f93e823d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.tsx @@ -31,6 +31,7 @@ export const GraphPreviewContainer: React.FC = () => { scopeId, isPreview, isPreviewMode, + dataFormattedForFieldBrowser, } = useDocumentDetailsContext(); const [visualizationInFlyoutEnabled] = useUiSetting$( @@ -49,16 +50,18 @@ export const GraphPreviewContainer: React.FC = () => { eventIds, timestamp = new Date().toISOString(), hasGraphRepresentation, + isAlert, } = useGraphPreview({ getFieldsData, ecsData: dataAsNestedObject, + dataFormattedForFieldBrowser, }); // TODO: default start and end might not capture the original event const { isLoading, isError, data } = useFetchGraphData({ req: { query: { - eventIds, + originEventIds: eventIds.map((id) => ({ id, isAlert })), start: `${timestamp}||-30m`, end: `${timestamp}||+30m`, }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx index ff003813f260d..e6f88498b2605 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx @@ -14,11 +14,7 @@ import { } from './test_ids'; import { HighlightedFieldsCell } from './highlighted_fields_cell'; import { DocumentDetailsContext } from '../../shared/context'; -import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; -import { LeftPanelInsightsTab } from '../../left'; import { TestProviders } from '../../../../common/mock'; -import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { useGetAgentStatus } from '../../../../management/hooks/agents/use_get_agent_status'; import { mockFlyoutApi } from '../../shared/mocks/mock_flyout_context'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; @@ -47,9 +43,6 @@ jest.mock('../../../../common/lib/kibana', () => { const useGetAgentStatusMock = useGetAgentStatus as jest.Mock; -jest.mock('../../../../common/hooks/use_experimental_features'); -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; - const panelContextValue = { eventId: 'event id', indexName: 'indexName', @@ -68,7 +61,6 @@ const renderHighlightedFieldsCell = (values: string[], field: string) => describe('', () => { beforeAll(() => { jest.mocked(useExpandableFlyoutApi).mockReturnValue(mockFlyoutApi); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); }); it('should render a basic cell', () => { @@ -83,23 +75,7 @@ describe('', () => { expect(getByTestId(HIGHLIGHTED_FIELDS_BASIC_CELL_TEST_ID)).toBeInTheDocument(); }); - it('should open left panel when clicking on the link within a a link cell when preview is disabled', () => { - const { getByTestId } = renderHighlightedFieldsCell(['value'], 'user.name'); - - getByTestId(HIGHLIGHTED_FIELDS_LINKED_CELL_TEST_ID).click(); - expect(mockFlyoutApi.openLeftPanel).toHaveBeenCalledWith({ - id: DocumentDetailsLeftPanelKey, - path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, - params: { - id: panelContextValue.eventId, - indexName: panelContextValue.indexName, - scopeId: panelContextValue.scopeId, - }, - }); - }); - - it('should open host preview when click on host when preview is not disabled', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('should open host preview when click on host', () => { const { getByTestId } = renderHighlightedFieldsCell(['test host'], 'host.name'); expect(getByTestId(HIGHLIGHTED_FIELDS_LINKED_CELL_TEST_ID)).toBeInTheDocument(); @@ -114,8 +90,7 @@ describe('', () => { }); }); - it('should open user preview when click on user when preview is not disabled', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('should open user preview when click on user', () => { const { getByTestId } = renderHighlightedFieldsCell(['test user'], 'user.name'); expect(getByTestId(HIGHLIGHTED_FIELDS_LINKED_CELL_TEST_ID)).toBeInTheDocument(); @@ -130,8 +105,7 @@ describe('', () => { }); }); - it('should open ip preview when click on ip when preview is not disabled', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + it('should open ip preview when click on ip', () => { const { getByTestId } = renderHighlightedFieldsCell(['100:XXX:XXX'], 'source.ip'); expect(getByTestId(HIGHLIGHTED_FIELDS_LINKED_CELL_TEST_ID)).toBeInTheDocument(); @@ -204,6 +178,7 @@ describe('', () => { expect(getByTestId(HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID)).toBeInTheDocument(); }); + it('should not render if values is null', () => { const { container } = render( diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx index e11dee4a74adf..b6fc98653f896 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx @@ -5,19 +5,14 @@ * 2.0. */ -import type { VFC } from 'react'; -import React, { useCallback, useMemo } from 'react'; -import { EuiFlexItem, EuiLink } from '@elastic/eui'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import type { FC } from 'react'; +import React, { useMemo } from 'react'; +import { EuiFlexItem } from '@elastic/eui'; import { getAgentTypeForAgentIdField } from '../../../../common/lib/endpoint/utils/get_agent_type_for_agent_id_field'; import type { ResponseActionAgentType } from '../../../../../common/endpoint/service/response_actions/constants'; import { AgentStatus } from '../../../../common/components/endpoint/agents/agent_status'; import { useDocumentDetailsContext } from '../../shared/context'; import { AGENT_STATUS_FIELD_NAME } from '../../../../timelines/components/timeline/body/renderers/constants'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; -import { LeftPanelInsightsTab } from '../../left'; -import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID, HIGHLIGHTED_FIELDS_BASIC_CELL_TEST_ID, @@ -44,26 +39,12 @@ export interface HighlightedFieldsCellProps { /** * Renders a component in the highlighted fields table cell based on the field name */ -export const HighlightedFieldsCell: VFC = ({ +export const HighlightedFieldsCell: FC = ({ values, field, originalField = '', }) => { - const { scopeId, eventId, indexName } = useDocumentDetailsContext(); - const { openLeftPanel } = useExpandableFlyoutApi(); - const isPreviewEnabled = !useIsExperimentalFeatureEnabled('entityAlertPreviewDisabled'); - - const goToInsightsEntities = useCallback(() => { - openLeftPanel({ - id: DocumentDetailsLeftPanelKey, - path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, - params: { - id: eventId, - indexName, - scopeId, - }, - }); - }, [eventId, indexName, openLeftPanel, scopeId]); + const { scopeId } = useDocumentDetailsContext(); const agentType: ResponseActionAgentType = useMemo(() => { return getAgentTypeForAgentIdField(originalField); @@ -79,20 +60,13 @@ export const HighlightedFieldsCell: VFC = ({ key={`${i}-${value}`} data-test-subj={`${value}-${HIGHLIGHTED_FIELDS_CELL_TEST_ID}`} > - {isPreviewEnabled && hasPreview(field) ? ( + {hasPreview(field) ? ( - ) : hasPreview(field) ? ( - - {value} - ) : field === AGENT_STATUS_FIELD_NAME ? ( { }; }); -jest.mock('../../../../common/hooks/use_experimental_features'); -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; - const mockUseGlobalTime = jest.fn().mockReturnValue({ from, to }); jest.mock('../../../../common/containers/use_global_time', () => { return { @@ -124,7 +117,6 @@ const renderHostEntityContent = () => describe('', () => { beforeAll(() => { jest.mocked(useExpandableFlyoutApi).mockReturnValue(mockFlyoutApi); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); (useMisconfigurationPreview as jest.Mock).mockReturnValue({}); (useVulnerabilitiesPreview as jest.Mock).mockReturnValue({}); (useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: false, items: {} }); @@ -204,28 +196,9 @@ describe('', () => { expect(getByTestId(ENTITIES_HOST_OVERVIEW_LAST_SEEN_TEST_ID)).toHaveTextContent('—'); }); - it('should navigate to left panel entities tab when clicking on title when feature flag is off', () => { - mockUseHostDetails.mockReturnValue([false, { hostDetails: hostData }]); - mockUseRiskScore.mockReturnValue({ data: riskLevel, isAuthorized: true }); - - const { getByTestId } = renderHostEntityContent(); - - getByTestId(ENTITIES_HOST_OVERVIEW_LINK_TEST_ID).click(); - expect(mockFlyoutApi.openLeftPanel).toHaveBeenCalledWith({ - id: DocumentDetailsLeftPanelKey, - path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, - params: { - id: panelContextValue.eventId, - indexName: panelContextValue.indexName, - scopeId: panelContextValue.scopeId, - }, - }); - }); - - it('should open host preview when clicking on title when feature flag is on', () => { + it('should open host preview when clicking on title', () => { mockUseHostDetails.mockReturnValue([false, { hostDetails: hostData }]); mockUseRiskScore.mockReturnValue({ data: riskLevel, isAuthorized: true }); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); const { getByTestId } = renderHostEntityContent(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.tsx index 9b60eefbb5f61..eb1ca093fbb03 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.tsx @@ -5,11 +5,10 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, - EuiLink, EuiText, EuiIcon, useEuiTheme, @@ -19,8 +18,6 @@ import { import { css } from '@emotion/css'; import { getOr } from 'lodash/fp'; import { i18n } from '@kbn/i18n'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { HOST_NAME_FIELD_NAME } from '../../../../timelines/components/timeline/body/renderers/constants'; import { useRiskScore } from '../../../../entity_analytics/api/hooks/use_risk_score'; import { useDocumentDetailsContext } from '../../shared/context'; @@ -44,7 +41,6 @@ import { LAST_SEEN, HOST_RISK_LEVEL, } from '../../../../overview/components/host_overview/translations'; -import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { ENTITIES_HOST_OVERVIEW_TEST_ID, ENTITIES_HOST_OVERVIEW_OS_FAMILY_TEST_ID, @@ -56,8 +52,6 @@ import { ENTITIES_HOST_OVERVIEW_MISCONFIGURATIONS_TEST_ID, ENTITIES_HOST_OVERVIEW_VULNERABILITIES_TEST_ID, } from './test_ids'; -import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; -import { LeftPanelInsightsTab } from '../../left'; import { RiskScoreDocTooltip } from '../../../../overview/components/common'; import { PreviewLink } from '../../../shared/components/preview_link'; import { MisconfigurationsInsight } from '../../shared/components/misconfiguration_insight'; @@ -85,21 +79,7 @@ export const HOST_PREVIEW_BANNER = { * Host preview content for the entities preview in right flyout. It contains ip addresses and risk level */ export const HostEntityOverview: React.FC = ({ hostName }) => { - const { eventId, indexName, scopeId } = useDocumentDetailsContext(); - const { openLeftPanel } = useExpandableFlyoutApi(); - const isPreviewEnabled = !useIsExperimentalFeatureEnabled('entityAlertPreviewDisabled'); - - const goToEntitiesTab = useCallback(() => { - openLeftPanel({ - id: DocumentDetailsLeftPanelKey, - path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, - params: { - id: eventId, - indexName, - scopeId, - }, - }); - }, [eventId, openLeftPanel, indexName, scopeId]); + const { scopeId } = useDocumentDetailsContext(); const { from, to } = useGlobalTime(); const { selectedPatterns } = useSourcererDataView(); @@ -212,34 +192,21 @@ export const HostEntityOverview: React.FC = ({ hostName - {isPreviewEnabled ? ( - - - {hostName} - - - ) : ( - + {hostName} - - )} + + diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.test.tsx index eec53dbe3d262..2c7abe5bb1d27 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.test.tsx @@ -9,7 +9,6 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import type { FieldSpec } from '@kbn/data-plugin/common'; import { DocumentDetailsContext } from '../../shared/context'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { EventFieldsData } from '../../../../common/components/event_details/types'; import { TableFieldValueCell } from './table_field_value_cell'; @@ -35,9 +34,6 @@ jest.mock('../../../../common/lib/kibana', () => { }; }); -jest.mock('../../../../common/hooks/use_experimental_features'); -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; - const panelContextValue = { eventId: 'event id', indexName: 'indexName', @@ -66,7 +62,6 @@ describe('TableFieldValueCell', () => { beforeAll(() => { jest.clearAllMocks(); jest.mocked(useExpandableFlyoutApi).mockReturnValue(mockFlyoutApi); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); }); describe('common behavior', () => { @@ -213,7 +208,7 @@ describe('TableFieldValueCell', () => { }); }); - it('should open preview when preview is not disabled', () => { + it('should open preview', () => { screen.getByTestId(`${FLYOUT_TABLE_PREVIEW_LINK_FIELD_TEST_ID}-0`).click(); expect(mockFlyoutApi.openPreviewPanel).toHaveBeenCalledWith({ diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.tsx index a0095bb8eadf0..17ea9980f1ee0 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.tsx @@ -8,7 +8,6 @@ import React, { memo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import type { FieldSpec } from '@kbn/data-plugin/common'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { getFieldFormat } from '../utils/get_field_format'; import type { EventFieldsData } from '../../../../common/components/event_details/types'; import { OverflowField } from '../../../../common/components/tables/helpers'; @@ -66,7 +65,6 @@ export const TableFieldValueCell = memo( values, isPreview, }: FieldValueCellProps) => { - const isPreviewEnabled = !useIsExperimentalFeatureEnabled('entityAlertPreviewDisabled'); if (values == null) { return null; } @@ -92,7 +90,7 @@ export const TableFieldValueCell = memo( {data.field === MESSAGE_FIELD_NAME ? ( - ) : isPreviewEnabled && hasPreview(data.field) ? ( + ) : hasPreview(data.field) ? ( { return { @@ -109,7 +102,6 @@ const renderUserEntityOverview = () => describe('', () => { beforeAll(() => { jest.mocked(useExpandableFlyoutApi).mockReturnValue(mockFlyoutApi); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); (useMisconfigurationPreview as jest.Mock).mockReturnValue({}); (useAlertsByStatus as jest.Mock).mockReturnValue({ isLoading: false, items: {} }); }); @@ -190,34 +182,9 @@ describe('', () => { expect(queryByTestId(ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID)).not.toBeInTheDocument(); }); - it('should navigate to left panel entities tab when clicking on title when feature flag is off', () => { - mockUseUserDetails.mockReturnValue([false, { userDetails: userData }]); - mockUseRiskScore.mockReturnValue({ data: riskLevel, isAuthorized: true }); - - const { getByTestId } = render( - - - - - - ); - - getByTestId(ENTITIES_USER_OVERVIEW_LINK_TEST_ID).click(); - expect(mockFlyoutApi.openLeftPanel).toHaveBeenCalledWith({ - id: DocumentDetailsLeftPanelKey, - path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, - params: { - id: panelContextValue.eventId, - indexName: panelContextValue.indexName, - scopeId: panelContextValue.scopeId, - }, - }); - }); - - it('should open user preview if feature flag is true', () => { + it('should open user preview', () => { mockUseUserDetails.mockReturnValue([false, { userDetails: userData }]); mockUseRiskScore.mockReturnValue({ data: riskLevel, isAuthorized: true }); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); const { getByTestId } = render( diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.tsx index 1008f6139cd67..22f889a61c54e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.tsx @@ -5,13 +5,12 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText, - EuiLink, useEuiTheme, useEuiFontSize, EuiSkeletonText, @@ -19,11 +18,6 @@ import { import { css } from '@emotion/css'; import { getOr } from 'lodash/fp'; import { i18n } from '@kbn/i18n'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; -import { LeftPanelInsightsTab } from '../../left'; -import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { useDocumentDetailsContext } from '../../shared/context'; import type { DescriptionList } from '../../../../../common/utility_types'; import { USER_NAME_FIELD_NAME } from '../../../../timelines/components/timeline/body/renderers/constants'; @@ -83,22 +77,7 @@ export const USER_PREVIEW_BANNER = { * User preview content for the entities preview in right flyout. It contains ip addresses and risk level */ export const UserEntityOverview: React.FC = ({ userName }) => { - const { eventId, indexName, scopeId } = useDocumentDetailsContext(); - const { openLeftPanel } = useExpandableFlyoutApi(); - - const isPreviewEnabled = !useIsExperimentalFeatureEnabled('entityAlertPreviewDisabled'); - - const goToEntitiesTab = useCallback(() => { - openLeftPanel({ - id: DocumentDetailsLeftPanelKey, - path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, - params: { - id: eventId, - indexName, - scopeId, - }, - }); - }, [eventId, openLeftPanel, indexName, scopeId]); + const { scopeId } = useDocumentDetailsContext(); const { from, to } = useGlobalTime(); const { selectedPatterns } = useSourcererDataView(); @@ -210,34 +189,21 @@ export const UserEntityOverview: React.FC = ({ userName - {isPreviewEnabled ? ( - - - {userName} - - - ) : ( - + {userName} - - )} + + diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/visualizations_section.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/visualizations_section.test.tsx index 6fb4d5d30b897..dc3b1f00e0d50 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/visualizations_section.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/visualizations_section.test.tsx @@ -106,6 +106,7 @@ describe('', () => { }); mockUseGraphPreview.mockReturnValue({ hasGraphRepresentation: true, + eventIds: [], }); mockUseFetchGraphData.mockReturnValue({ isLoading: false, diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/visualizations_section.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/visualizations_section.tsx index 23bea1f8fecdd..467171cd49f2a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/visualizations_section.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/right/components/visualizations_section.tsx @@ -28,7 +28,8 @@ const KEY = 'visualizations'; */ export const VisualizationsSection = memo(() => { const expanded = useExpandSection({ title: KEY, defaultValue: false }); - const { dataAsNestedObject, getFieldsData } = useDocumentDetailsContext(); + const { dataAsNestedObject, getFieldsData, dataFormattedForFieldBrowser } = + useDocumentDetailsContext(); const [visualizationInFlyoutEnabled] = useUiSetting$( ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING @@ -42,6 +43,7 @@ export const VisualizationsSection = memo(() => { const { hasGraphRepresentation } = useGraphPreview({ getFieldsData, ecsData: dataAsNestedObject, + dataFormattedForFieldBrowser, }); const shouldShowGraphPreview = diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/shared/hooks/use_graph_preview.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/shared/hooks/use_graph_preview.test.tsx index 453f897d4e188..cf1ee82078395 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/shared/hooks/use_graph_preview.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/shared/hooks/use_graph_preview.test.tsx @@ -5,15 +5,18 @@ * 2.0. */ -import type { RenderHookResult } from '@testing-library/react'; +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import { renderHook } from '@testing-library/react'; -import type { UseGraphPreviewParams, UseGraphPreviewResult } from './use_graph_preview'; +import type { UseGraphPreviewParams } from './use_graph_preview'; import { useGraphPreview } from './use_graph_preview'; import type { GetFieldsData } from './use_get_fields_data'; import { mockFieldData } from '../mocks/mock_get_fields_data'; +import { mockDataFormattedForFieldBrowser } from '../mocks/mock_data_formatted_for_field_browser'; -const mockGetFieldsData: GetFieldsData = (field: string) => { - if (field === 'kibana.alert.original_event.id') { +const alertMockGetFieldsData: GetFieldsData = (field: string) => { + if (field === 'kibana.alert.uuid') { + return 'alertId'; + } else if (field === 'kibana.alert.original_event.id') { return 'eventId'; } else if (field === 'actor.entity.id') { return 'actorId'; @@ -24,18 +27,36 @@ const mockGetFieldsData: GetFieldsData = (field: string) => { return mockFieldData[field]; }; -describe('useGraphPreview', () => { - let hookResult: RenderHookResult; +const alertMockDataFormattedForFieldBrowser = mockDataFormattedForFieldBrowser; + +const eventMockGetFieldsData: GetFieldsData = (field: string) => { + if (field === 'kibana.alert.uuid') { + return; + } else if (field === 'kibana.alert.original_event.id') { + return; + } else if (field === 'event.id') { + return 'eventId'; + } else if (field === 'actor.entity.id') { + return 'actorId'; + } else if (field === 'target.entity.id') { + return 'targetId'; + } + return mockFieldData[field]; +}; + +const eventMockDataFormattedForFieldBrowser: TimelineEventsDetailsItem[] = []; + +describe('useGraphPreview', () => { it(`should return false when missing actor`, () => { const getFieldsData: GetFieldsData = (field: string) => { if (field === 'actor.entity.id') { return; } - return mockGetFieldsData(field); + return alertMockGetFieldsData(field); }; - hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { + const hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { initialProps: { getFieldsData, ecsData: { @@ -44,37 +65,41 @@ describe('useGraphPreview', () => { action: ['action'], }, }, + dataFormattedForFieldBrowser: alertMockDataFormattedForFieldBrowser, }, }); - const { hasGraphRepresentation, timestamp, eventIds, actorIds, action, targetIds } = - hookResult.result.current; - expect(hasGraphRepresentation).toEqual(false); - expect(timestamp).toEqual(mockFieldData['@timestamp'][0]); - expect(eventIds).toEqual(['eventId']); - expect(actorIds).toEqual([]); - expect(targetIds).toEqual(['targetId']); - expect(action).toEqual(['action']); + expect(hookResult.result.current).toStrictEqual({ + hasGraphRepresentation: false, + timestamp: mockFieldData['@timestamp'][0], + eventIds: ['eventId'], + actorIds: [], + action: ['action'], + targetIds: ['targetId'], + isAlert: true, + }); }); it(`should return false when missing event.action`, () => { - hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { + const hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { initialProps: { - getFieldsData: mockGetFieldsData, + getFieldsData: alertMockGetFieldsData, ecsData: { _id: 'id', }, + dataFormattedForFieldBrowser: alertMockDataFormattedForFieldBrowser, }, }); - const { hasGraphRepresentation, timestamp, eventIds, actorIds, action, targetIds } = - hookResult.result.current; - expect(hasGraphRepresentation).toEqual(false); - expect(timestamp).toEqual(mockFieldData['@timestamp'][0]); - expect(eventIds).toEqual(['eventId']); - expect(actorIds).toEqual(['actorId']); - expect(targetIds).toEqual(['targetId']); - expect(action).toEqual(undefined); + expect(hookResult.result.current).toStrictEqual({ + hasGraphRepresentation: false, + timestamp: mockFieldData['@timestamp'][0], + eventIds: ['eventId'], + actorIds: ['actorId'], + action: undefined, + targetIds: ['targetId'], + isAlert: true, + }); }); it(`should return false when missing target`, () => { @@ -82,26 +107,28 @@ describe('useGraphPreview', () => { if (field === 'target.entity.id') { return; } - return mockGetFieldsData(field); + return alertMockGetFieldsData(field); }; - hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { + const hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { initialProps: { getFieldsData, ecsData: { _id: 'id', }, + dataFormattedForFieldBrowser: alertMockDataFormattedForFieldBrowser, }, }); - const { hasGraphRepresentation, timestamp, eventIds, actorIds, action, targetIds } = - hookResult.result.current; - expect(hasGraphRepresentation).toEqual(false); - expect(timestamp).toEqual(mockFieldData['@timestamp'][0]); - expect(eventIds).toEqual(['eventId']); - expect(actorIds).toEqual(['actorId']); - expect(targetIds).toEqual([]); - expect(action).toEqual(undefined); + expect(hookResult.result.current).toStrictEqual({ + hasGraphRepresentation: false, + timestamp: mockFieldData['@timestamp'][0], + eventIds: ['eventId'], + actorIds: ['actorId'], + action: undefined, + targetIds: [], + isAlert: true, + }); }); it(`should return false when missing original_event.id`, () => { @@ -110,10 +137,10 @@ describe('useGraphPreview', () => { return; } - return mockGetFieldsData(field); + return alertMockGetFieldsData(field); }; - hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { + const hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { initialProps: { getFieldsData, ecsData: { @@ -122,17 +149,19 @@ describe('useGraphPreview', () => { action: ['action'], }, }, + dataFormattedForFieldBrowser: alertMockDataFormattedForFieldBrowser, }, }); - const { hasGraphRepresentation, timestamp, eventIds, actorIds, action, targetIds } = - hookResult.result.current; - expect(hasGraphRepresentation).toEqual(false); - expect(timestamp).toEqual(mockFieldData['@timestamp'][0]); - expect(eventIds).toEqual([]); - expect(actorIds).toEqual(['actorId']); - expect(targetIds).toEqual(['targetId']); - expect(action).toEqual(['action']); + expect(hookResult.result.current).toStrictEqual({ + hasGraphRepresentation: false, + timestamp: mockFieldData['@timestamp'][0], + eventIds: [], + actorIds: ['actorId'], + action: ['action'], + targetIds: ['targetId'], + isAlert: true, + }); }); it(`should return false when timestamp is missing`, () => { @@ -141,10 +170,10 @@ describe('useGraphPreview', () => { return; } - return mockGetFieldsData(field); + return alertMockGetFieldsData(field); }; - hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { + const hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { initialProps: { getFieldsData, ecsData: { @@ -153,45 +182,53 @@ describe('useGraphPreview', () => { action: ['action'], }, }, + dataFormattedForFieldBrowser: alertMockDataFormattedForFieldBrowser, }, }); - const { hasGraphRepresentation, timestamp, eventIds, actorIds, action, targetIds } = - hookResult.result.current; - expect(hasGraphRepresentation).toEqual(false); - expect(timestamp).toEqual(null); - expect(eventIds).toEqual(['eventId']); - expect(actorIds).toEqual(['actorId']); - expect(targetIds).toEqual(['targetId']); - expect(action).toEqual(['action']); + expect(hookResult.result.current).toStrictEqual({ + hasGraphRepresentation: false, + timestamp: null, + eventIds: ['eventId'], + actorIds: ['actorId'], + action: ['action'], + targetIds: ['targetId'], + isAlert: true, + }); }); - it(`should return true when alert is has graph preview`, () => { - hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { + it(`should return true when event has graph graph preview`, () => { + const hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { initialProps: { - getFieldsData: mockGetFieldsData, + getFieldsData: eventMockGetFieldsData, ecsData: { _id: 'id', event: { action: ['action'], }, }, + dataFormattedForFieldBrowser: eventMockDataFormattedForFieldBrowser, }, }); - const { hasGraphRepresentation, timestamp, eventIds, actorIds, action, targetIds } = - hookResult.result.current; - expect(hasGraphRepresentation).toEqual(true); - expect(timestamp).toEqual(mockFieldData['@timestamp'][0]); - expect(eventIds).toEqual(['eventId']); - expect(actorIds).toEqual(['actorId']); - expect(targetIds).toEqual(['targetId']); - expect(action).toEqual(['action']); + expect(hookResult.result.current).toStrictEqual({ + hasGraphRepresentation: true, + timestamp: mockFieldData['@timestamp'][0], + eventIds: ['eventId'], + actorIds: ['actorId'], + action: ['action'], + targetIds: ['targetId'], + isAlert: false, + }); }); - it(`should return true when alert is has graph preview with multiple values`, () => { + it(`should return true when event has graph preview with multiple values`, () => { const getFieldsData: GetFieldsData = (field: string) => { - if (field === 'kibana.alert.original_event.id') { + if (field === 'kibana.alert.uuid') { + return; + } else if (field === 'kibana.alert.original_event.id') { + return; + } else if (field === 'event.id') { return ['id1', 'id2']; } else if (field === 'actor.entity.id') { return ['actorId1', 'actorId2']; @@ -202,7 +239,7 @@ describe('useGraphPreview', () => { return mockFieldData[field]; }; - hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { + const hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { initialProps: { getFieldsData, ecsData: { @@ -211,16 +248,82 @@ describe('useGraphPreview', () => { action: ['action1', 'action2'], }, }, + dataFormattedForFieldBrowser: eventMockDataFormattedForFieldBrowser, }, }); - const { hasGraphRepresentation, timestamp, eventIds, actorIds, action, targetIds } = - hookResult.result.current; - expect(hasGraphRepresentation).toEqual(true); - expect(timestamp).toEqual(mockFieldData['@timestamp'][0]); - expect(eventIds).toEqual(['id1', 'id2']); - expect(actorIds).toEqual(['actorId1', 'actorId2']); - expect(action).toEqual(['action1', 'action2']); - expect(targetIds).toEqual(['targetId1', 'targetId2']); + expect(hookResult.result.current).toStrictEqual({ + hasGraphRepresentation: true, + timestamp: mockFieldData['@timestamp'][0], + eventIds: ['id1', 'id2'], + actorIds: ['actorId1', 'actorId2'], + action: ['action1', 'action2'], + targetIds: ['targetId1', 'targetId2'], + isAlert: false, + }); + }); + + it(`should return true when alert has graph preview`, () => { + const hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { + initialProps: { + getFieldsData: alertMockGetFieldsData, + ecsData: { + _id: 'id', + event: { + action: ['action'], + }, + }, + dataFormattedForFieldBrowser: alertMockDataFormattedForFieldBrowser, + }, + }); + + expect(hookResult.result.current).toStrictEqual({ + hasGraphRepresentation: true, + timestamp: mockFieldData['@timestamp'][0], + eventIds: ['eventId'], + actorIds: ['actorId'], + action: ['action'], + targetIds: ['targetId'], + isAlert: true, + }); + }); + + it(`should return true when alert has graph preview with multiple values`, () => { + const getFieldsData: GetFieldsData = (field: string) => { + if (field === 'kibana.alert.uuid') { + return 'alertId'; + } else if (field === 'kibana.alert.original_event.id') { + return ['id1', 'id2']; + } else if (field === 'actor.entity.id') { + return ['actorId1', 'actorId2']; + } else if (field === 'target.entity.id') { + return ['targetId1', 'targetId2']; + } + + return mockFieldData[field]; + }; + + const hookResult = renderHook((props: UseGraphPreviewParams) => useGraphPreview(props), { + initialProps: { + getFieldsData, + ecsData: { + _id: 'id', + event: { + action: ['action1', 'action2'], + }, + }, + dataFormattedForFieldBrowser: alertMockDataFormattedForFieldBrowser, + }, + }); + + expect(hookResult.result.current).toStrictEqual({ + hasGraphRepresentation: true, + timestamp: mockFieldData['@timestamp'][0], + eventIds: ['id1', 'id2'], + actorIds: ['actorId1', 'actorId2'], + action: ['action1', 'action2'], + targetIds: ['targetId1', 'targetId2'], + isAlert: true, + }); }); }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/shared/hooks/use_graph_preview.ts b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/shared/hooks/use_graph_preview.ts index 48233afab02df..8f05b87844fb2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/shared/hooks/use_graph_preview.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/shared/hooks/use_graph_preview.ts @@ -5,10 +5,12 @@ * 2.0. */ +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { get } from 'lodash/fp'; import type { GetFieldsData } from './use_get_fields_data'; import { getField, getFieldArray } from '../utils'; +import { useBasicDataFromDetailsData } from './use_basic_data_from_details_data'; export interface UseGraphPreviewParams { /** @@ -20,6 +22,11 @@ export interface UseGraphPreviewParams { * An object with top level fields from the ECS object */ ecsData: Ecs; + + /** + * An array of field objects with category and value + */ + dataFormattedForFieldBrowser: TimelineEventsDetailsItem[]; } /** * Interface for the result of the useGraphPreview hook @@ -54,6 +61,11 @@ export interface UseGraphPreviewResult { * Boolean indicating if the event is has a graph representation (contains event ids, actor ids and action) */ hasGraphRepresentation: boolean; + + /** + * Boolean indicating if the event is an alert or not + */ + isAlert: boolean; } /** @@ -62,6 +74,7 @@ export interface UseGraphPreviewResult { export const useGraphPreview = ({ getFieldsData, ecsData, + dataFormattedForFieldBrowser, }: UseGraphPreviewParams): UseGraphPreviewResult => { const timestamp = getField(getFieldsData('@timestamp')); const originalEventId = getFieldsData('kibana.alert.original_event.id'); @@ -77,6 +90,7 @@ export const useGraphPreview = ({ actorIds.length > 0 && eventIds.length > 0 && targetIds.length > 0; + const { isAlert } = useBasicDataFromDetailsData(dataFormattedForFieldBrowser); - return { timestamp, eventIds, actorIds, action, targetIds, hasGraphRepresentation }; + return { timestamp, eventIds, actorIds, action, targetIds, hasGraphRepresentation, isAlert }; }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/common/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/management/common/translations.ts index 6929452e5d9e9..50885a9db6b6a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/common/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/common/translations.ts @@ -279,7 +279,7 @@ Command Examples for Running Scripts: 3. Executes a raw script provided entirely within the "--Raw" flag. - runscript --Raw="Get-ChildItem." + runscript --Raw=\`\`\`Get-ChildItem.\`\`\` 4. Executes a script located on the remote host at the specified path with the provided command-line arguments. diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.tsx b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.tsx index 43ff3ffca5a62..09d1e45f24c45 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response.tsx @@ -10,6 +10,8 @@ import type { ActionDetails, MaybeImmutable, ResponseActionExecuteOutputContent, + ResponseActionRunScriptOutputContent, + ResponseActionRunScriptParameters, ResponseActionsExecuteParameters, } from '../../../../common/endpoint/types'; import { EXECUTE_FILE_LINK_TITLE } from '../endpoint_response_actions_list/translations'; @@ -18,14 +20,18 @@ import { ExecuteActionHostResponseOutput } from './execute_action_host_response_ export interface ExecuteActionHostResponseProps { action: MaybeImmutable< - ActionDetails + | ActionDetails + | ActionDetails >; agentId?: string; canAccessFileDownloadLink: boolean; 'data-test-subj'?: string; textSize?: 'xs' | 's'; + hideFile?: boolean; + hideContext?: boolean; } +// Note: also used for RunScript command export const ExecuteActionHostResponse = memo( ({ action, @@ -33,6 +39,8 @@ export const ExecuteActionHostResponse = memo( canAccessFileDownloadLink, textSize = 's', 'data-test-subj': dataTestSubj, + hideFile, + hideContext, }) => { const outputContent = useMemo( () => @@ -44,21 +52,24 @@ export const ExecuteActionHostResponse = memo( return ( <> - - - - + {!hideFile && ( + + + + + )} {outputContent && ( )} diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response_output.tsx b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response_output.tsx index f24f18e149393..4e6161b8767d9 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response_output.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_execute_action/execute_action_host_response_output.tsx @@ -98,6 +98,7 @@ interface ShellInfoContentProps { textSize?: 's' | 'xs'; title: string; } + const ShellInfoContent = memo(({ content, textSize, title }) => ( @@ -178,10 +179,12 @@ export interface ExecuteActionHostResponseOutputProps { outputContent: ResponseActionExecuteOutputContent; 'data-test-subj'?: string; textSize?: 's' | 'xs'; + hideContext?: boolean; } +// Note: also used for RunScript command export const ExecuteActionHostResponseOutput = memo( - ({ outputContent, 'data-test-subj': dataTestSubj, textSize = 'xs' }) => { + ({ outputContent, 'data-test-subj': dataTestSubj, textSize = 'xs', hideContext }) => { const contextContent = useMemo( () => ( <> @@ -216,14 +219,16 @@ export const ExecuteActionHostResponseOutput = memo - - - + {!hideContext && ( + + + + )} {outputContent.stderr.length > 0 && ( <> diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/run_script_action.tsx b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/run_script_action.tsx new file mode 100644 index 0000000000000..e2ed358455027 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/run_script_action.tsx @@ -0,0 +1,96 @@ +/* + * 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 React, { memo, useMemo } from 'react'; + +import { i18n } from '@kbn/i18n'; +import { ExecuteActionHostResponse } from '../../endpoint_execute_action'; +import { useSendRunScriptEndpoint } from '../../../hooks/response_actions/use_send_run_script_endpoint_request'; +import type { RunScriptActionRequestBody } from '../../../../../common/api/endpoint'; +import { useConsoleActionSubmitter } from '../hooks/use_console_action_submitter'; +import type { + ResponseActionRunScriptOutputContent, + ResponseActionRunScriptParameters, +} from '../../../../../common/endpoint/types'; +import type { ActionRequestComponentProps } from '../types'; + +export const RunScriptActionResult = memo< + ActionRequestComponentProps< + { + Raw?: string; + HostPath?: string; + CloudFile?: string; + CommandLine?: string; + Timeout?: number; + comment?: string; + }, + ResponseActionRunScriptOutputContent, + ResponseActionRunScriptParameters + > +>(({ command, setStore, store, status, setStatus, ResultComponent }) => { + const actionCreator = useSendRunScriptEndpoint(); + const actionRequestBody = useMemo(() => { + const { endpointId, agentType } = command.commandDefinition?.meta ?? {}; + + if (!endpointId) { + return; + } + return { + agent_type: agentType, + endpoint_ids: [endpointId], + parameters: { + raw: command.args.args.Raw?.[0], + hostPath: command.args.args.HostPath?.[0], + cloudFile: command.args.args.CloudFile?.[0], + commandLine: command.args.args.CommandLine?.[0], + timeout: command.args.args.Timeout?.[0], + }, + comment: command.args.args?.comment?.[0], + }; + }, [command]); + + const { result, actionDetails: completedActionDetails } = useConsoleActionSubmitter< + RunScriptActionRequestBody, + ResponseActionRunScriptOutputContent, + ResponseActionRunScriptParameters + >({ + ResultComponent, + setStore, + store, + status, + setStatus, + actionCreator, + actionRequestBody, + dataTestSubj: 'runscript', + }); + + if (!completedActionDetails || !completedActionDetails.wasSuccessful) { + return result; + } + + return ( + + + + ); +}); +RunScriptActionResult.displayName = 'RunScriptActionResult'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts index 8c99186f69d93..22d138dea3586 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { RunScriptActionResult } from '../command_render_components/run_script_action'; import type { CommandArgDefinition } from '../../console/types'; import { isAgentTypeAndActionSupported } from '../../../../common/lib/endpoint'; import { getRbacControl } from '../../../../../common/endpoint/service/response_actions/utils'; @@ -531,14 +532,14 @@ export const getEndpointConsoleCommands = ({ aboutInfo: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.about, isSupported: doesEndpointSupportCommand('runscript'), }), - RenderComponent: () => null, + RenderComponent: RunScriptActionResult, meta: { agentType, endpointId: endpointAgentId, capabilities: endpointCapabilities, privileges: endpointPrivileges, }, - exampleUsage: `runscript --Raw="Get-ChildItem ." --CommandLine=""`, + exampleUsage: `runscript --Raw=\`\`\`Get-ChildItem .\`\`\` --CommandLine=""`, helpUsage: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.helpUsage, exampleInstruction: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.about, validate: capabilitiesAndPrivilegesValidator(agentType), diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_log_expanded_tray.tsx b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_log_expanded_tray.tsx index cba1d0aee41b4..53f2c89ac84fc 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_log_expanded_tray.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_log_expanded_tray.tsx @@ -23,6 +23,7 @@ import { isExecuteAction, isGetFileAction, isProcessesAction, + isRunScriptAction, isUploadAction, } from '../../../../../common/endpoint/service/response_actions/type_guards'; import { EndpointUploadActionResult } from '../../endpoint_upload_action_result'; @@ -209,6 +210,30 @@ const OutputContent = memo<{ ); } + if (isRunScriptAction(action)) { + return ( + + {action.agents.map((agentId) => ( +
    + {OUTPUT_MESSAGES.wasSuccessful(command)} + +
    + ))} +
    + ); + } + + // CrowdStrike Isolate/Release actions if (action.agentType === 'crowdstrike') { return <>{OUTPUT_MESSAGES.submittedSuccessfully(command)}; } diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/hooks/response_actions/use_send_run_script_endpoint_request.test.ts b/x-pack/solutions/security/plugins/security_solution/public/management/hooks/response_actions/use_send_run_script_endpoint_request.test.ts new file mode 100644 index 0000000000000..39eb3728162dc --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/management/hooks/response_actions/use_send_run_script_endpoint_request.test.ts @@ -0,0 +1,81 @@ +/* + * 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 { useMutation as _useMutation } from '@tanstack/react-query'; +import type { AppContextTestRender } from '../../../common/mock/endpoint'; +import type { RenderHookResult } from '@testing-library/react'; +import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; +import { responseActionsHttpMocks } from '../../mocks/response_actions_http_mocks'; +import { RUN_SCRIPT_ROUTE } from '../../../../common/endpoint/constants'; +import type { RunScriptActionRequestBody } from '../../../../common/api/endpoint'; +import type { + RunScriptRequestCustomOptions, + UseSendRunScriptRequestResult, +} from './use_send_run_script_endpoint_request'; +import { useSendRunScriptEndpoint } from './use_send_run_script_endpoint_request'; + +const useMutationMock = _useMutation as jest.Mock; + +jest.mock('@tanstack/react-query', () => { + const actualReactQueryModule = jest.requireActual('@tanstack/react-query'); + + return { + ...actualReactQueryModule, + useMutation: jest.fn((...args) => actualReactQueryModule.useMutation(...args)), + }; +}); + +const runScriptPayload: RunScriptActionRequestBody = { + endpoint_ids: ['test-endpoint-id'], + agent_type: 'crowdstrike', + parameters: { raw: 'ls' }, +}; + +describe('When using the `useSendRunScriptRequest()` hook', () => { + let customOptions: RunScriptRequestCustomOptions; + let http: AppContextTestRender['coreStart']['http']; + let apiMocks: ReturnType; + let renderHook: () => RenderHookResult< + UseSendRunScriptRequestResult, + RunScriptRequestCustomOptions + >; + + beforeEach(() => { + const testContext = createAppRootMockRenderer(); + + http = testContext.coreStart.http; + apiMocks = responseActionsHttpMocks(http); + customOptions = {}; + + renderHook = () => { + return testContext.renderHook(() => useSendRunScriptEndpoint(customOptions)); + }; + }); + + it('should call the `runScript` API with correct payload', async () => { + const { + result: { + current: { mutateAsync }, + }, + } = renderHook(); + await mutateAsync(runScriptPayload); + + expect(apiMocks.responseProvider.runscript).toHaveBeenCalledWith({ + body: JSON.stringify(runScriptPayload), + path: RUN_SCRIPT_ROUTE, + version: '2023-10-31', + }); + }); + + it('should allow custom options to be passed to ReactQuery', async () => { + customOptions.mutationKey = ['pqr-abc']; + customOptions.cacheTime = 10; + renderHook(); + + expect(useMutationMock).toHaveBeenCalledWith(expect.any(Function), customOptions); + }); +}); diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/hooks/response_actions/use_send_run_script_endpoint_request.ts b/x-pack/solutions/security/plugins/security_solution/public/management/hooks/response_actions/use_send_run_script_endpoint_request.ts new file mode 100644 index 0000000000000..f4dd937fe3008 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/management/hooks/response_actions/use_send_run_script_endpoint_request.ts @@ -0,0 +1,40 @@ +/* + * 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 type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query'; +import type { IHttpFetchError } from '@kbn/core-http-browser'; +import { useMutation } from '@tanstack/react-query'; +import type { RunScriptActionRequestBody } from '../../../../common/api/endpoint'; +import { KibanaServices } from '../../../common/lib/kibana'; +import { RUN_SCRIPT_ROUTE } from '../../../../common/endpoint/constants'; +import type { ResponseActionApiResponse } from '../../../../common/endpoint/types'; + +export type RunScriptRequestCustomOptions = UseMutationOptions< + ResponseActionApiResponse, + IHttpFetchError, + RunScriptActionRequestBody +>; + +export type UseSendRunScriptRequestResult = UseMutationResult< + ResponseActionApiResponse, + IHttpFetchError, + RunScriptActionRequestBody +>; + +export const useSendRunScriptEndpoint = ( + options?: RunScriptRequestCustomOptions +): UseSendRunScriptRequestResult => { + return useMutation( + (runScriptActionReqBody) => { + return KibanaServices.get().http.post(RUN_SCRIPT_ROUTE, { + body: JSON.stringify(runScriptActionReqBody), + version: '2023-10-31', + }); + }, + options + ); +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/mocks/response_actions_http_mocks.ts b/x-pack/solutions/security/plugins/security_solution/public/management/mocks/response_actions_http_mocks.ts index 256484f8d0e92..e8307895c3c4c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/mocks/response_actions_http_mocks.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/mocks/response_actions_http_mocks.ts @@ -17,6 +17,7 @@ import { GET_PROCESSES_ROUTE, ISOLATE_HOST_ROUTE_V2, KILL_PROCESS_ROUTE, + RUN_SCRIPT_ROUTE, SCAN_ROUTE, SUSPEND_PROCESS_ROUTE, UNISOLATE_HOST_ROUTE_V2, @@ -42,6 +43,8 @@ import type { ResponseActionScanParameters, ResponseActionUploadOutputContent, ResponseActionUploadParameters, + ResponseActionRunScriptOutputContent, + ResponseActionRunScriptParameters, } from '../../../common/endpoint/types'; export type ResponseActionsHttpMocksInterface = ResponseProvidersInterface<{ @@ -73,6 +76,8 @@ export type ResponseActionsHttpMocksInterface = ResponseProvidersInterface<{ >; scan: () => ActionDetailsApiResponse; + + runscript: () => ActionDetailsApiResponse; }>; export const responseActionsHttpMocks = httpHandlerMockFactory([ @@ -273,6 +278,25 @@ export const responseActionsHttpMocks = httpHandlerMockFactory => { + const generator = new EndpointActionGenerator('seed'); + const response = generator.generateActionDetails< + ResponseActionRunScriptOutputContent, + ResponseActionRunScriptParameters + >({ + command: 'runscript', + }); + return { data: response }; }, }, diff --git a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/response_actions.ts b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/response_actions.ts index 1987a019f8887..d54df140b3b4c 100644 --- a/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/response_actions.ts +++ b/x-pack/solutions/security/plugins/security_solution/scripts/endpoint/common/response_actions.ts @@ -27,6 +27,7 @@ import type { ResponseActionGetFileParameters, EndpointActionResponseDataOutput, ResponseActionScanOutputContent, + ResponseActionRunScriptOutputContent, } from '../../../common/endpoint/types'; import { getFileDownloadId } from '../../../common/endpoint/service/response_actions/get_file_download_id'; import { @@ -138,6 +139,15 @@ export const sendEndpointActionResponse = async ( .content as unknown as ResponseActionExecuteOutputContent ).stderr = 'execute command timed out'; } + if ( + endpointResponse.EndpointActions.data.command === 'runscript' && + endpointResponse.EndpointActions.data.output + ) { + ( + endpointResponse.EndpointActions.data.output + .content as unknown as ResponseActionRunScriptOutputContent + ).stderr = 'runscript command timed out'; + } } await esClient.index({ diff --git a/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts b/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts index 0c505b12c129d..25fcb30be4949 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts @@ -11,8 +11,13 @@ import { CROWDSTRIKE_CONNECTOR_ID, } from '@kbn/stack-connectors-plugin/common/crowdstrike/constants'; import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; -import type { CrowdstrikeBaseApiResponse } from '@kbn/stack-connectors-plugin/common/crowdstrike/types'; +import type { + CrowdstrikeBaseApiResponse, + CrowdStrikeExecuteRTRResponse, +} from '@kbn/stack-connectors-plugin/common/crowdstrike/types'; import { v4 as uuidv4 } from 'uuid'; + +import { mapParametersToCrowdStrikeArguments } from './utils'; import type { CrowdstrikeActionRequestCommonMeta } from '../../../../../../common/endpoint/types/crowdstrike'; import type { CommonResponseActionMethodOptions, @@ -305,15 +310,99 @@ export class CrowdstrikeActionsClient extends ResponseActionsClientImpl { ): Promise< ActionDetails > { - // TODO: just a placeholder for now - return Promise.resolve({ output: 'runscript', code: 200 }) as never as ActionDetails< - ResponseActionRunScriptOutputContent, - ResponseActionRunScriptParameters - >; + const reqIndexOptions: ResponseActionsClientWriteActionRequestToEndpointIndexOptions = { + ...actionRequest, + ...this.getMethodOptions(options), + command: 'runscript', + }; + + let actionResponse: ActionTypeExecutorResult | undefined; + if (!reqIndexOptions.error) { + let error = (await this.validateRequest(reqIndexOptions)).error; + if (!error) { + if (!reqIndexOptions.actionId) { + reqIndexOptions.actionId = uuidv4(); + } + + try { + actionResponse = (await this.sendAction(SUB_ACTION.EXECUTE_ADMIN_RTR, { + actionParameters: { comment: this.buildExternalComment(reqIndexOptions) }, + command: mapParametersToCrowdStrikeArguments('runscript', actionRequest.parameters), + endpoint_ids: actionRequest.endpoint_ids, + })) as ActionTypeExecutorResult; + } catch (err) { + error = err; + } + } + + reqIndexOptions.error = error?.message; + + if (!this.options.isAutomated && error) { + throw error; + } + } + + const actionRequestDoc = await this.writeActionRequestToEndpointIndex(reqIndexOptions); + + // Ensure actionResponse is assigned before using it + if (actionResponse) { + await this.completeCrowdstrikeBatchAction(actionResponse, actionRequestDoc); + } + + await this.updateCases({ + command: reqIndexOptions.command, + caseIds: reqIndexOptions.case_ids, + alertIds: reqIndexOptions.alert_ids, + actionId: actionRequestDoc.EndpointActions.action_id, + hosts: actionRequest.endpoint_ids.map((agentId) => { + return { + hostId: agentId, + hostname: actionRequestDoc.EndpointActions.data.hosts?.[agentId].name ?? '', + }; + }), + comment: reqIndexOptions.comment, + }); + + return this.fetchActionDetails(actionRequestDoc.EndpointActions.action_id); + } + + private async completeCrowdstrikeBatchAction( + actionResponse: ActionTypeExecutorResult, + doc: LogsEndpointAction + ): Promise { + const agentId = doc.agent.id as string; + const stdout = actionResponse.data?.combined.resources[agentId].stdout || ''; + const stderr = actionResponse.data?.combined.resources[agentId].stderr || ''; + const error = actionResponse.data?.combined.resources[agentId].errors?.[0]; + const options = { + actionId: doc.EndpointActions.action_id, + agentId, + data: { + ...doc.EndpointActions.data, + output: { + content: { + stdout, + stderr, + code: '200', + }, + type: 'text' as const, + }, + }, + ...(error + ? { + error: { + code: error.code, + message: `Crowdstrike action failed: ${error.message}`, + }, + } + : {}), + }; + + await this.writeActionResponseToEndpointIndex(options); } private async completeCrowdstrikeAction( - actionResponse: ActionTypeExecutorResult | undefined, + actionResponse: ActionTypeExecutorResult, doc: LogsEndpointAction ): Promise { const options = { diff --git a/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/utils.test.ts b/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/utils.test.ts new file mode 100644 index 0000000000000..f961c7a3d1d6b --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/utils.test.ts @@ -0,0 +1,51 @@ +/* + * 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 { mapParametersToCrowdStrikeArguments } from './utils'; + +describe('mapParametersToCrowdStrikeArguments', () => { + it('returns command with single word parameter as is', () => { + const result = mapParametersToCrowdStrikeArguments('runscript', { raw: 'echo Hello' }); + expect(result).toBe('runscript --Raw=```echo Hello```'); + }); + + it('wraps multi-word parameter in triple backticks', () => { + const result = mapParametersToCrowdStrikeArguments('runscript', { + commandLine: 'echo Hello World', + }); + expect(result).toBe('runscript --CommandLine=```echo Hello World```'); + }); + + it('leaves parameter already wrapped in triple backticks unchanged', () => { + const result = mapParametersToCrowdStrikeArguments('runscript', { + commandLine: '```echo Hello World```', + }); + expect(result).toBe('runscript --CommandLine=```echo Hello World```'); + }); + + it('trims spaces from parameter values', () => { + const result = mapParametersToCrowdStrikeArguments('runscript', { raw: ' echo Hello ' }); + expect(result).toBe('runscript --Raw=```echo Hello```'); + }); + + it('handles multiple parameters correctly', () => { + const result = mapParametersToCrowdStrikeArguments('runscript', { + raw: 'echo Hello', + commandLine: 'echo Hello World', + hostPath: '/home/user', + cloudFile: 'file.txt', + }); + expect(result).toBe( + 'runscript --Raw=```echo Hello``` --CommandLine=```echo Hello World``` --HostPath=/home/user --CloudFile=file.txt' + ); + }); + + it('returns command with no parameters correctly', () => { + const result = mapParametersToCrowdStrikeArguments('runscript', {}); + expect(result).toBe('runscript '); + }); +}); diff --git a/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/utils.ts b/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/utils.ts new file mode 100644 index 0000000000000..2ec2ec2bb0cf8 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/utils.ts @@ -0,0 +1,43 @@ +/* + * 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 { upperFirst } from 'lodash'; +import type { RunScriptActionRequestBody } from '../../../../../../common/api/endpoint'; + +export const mapParametersToCrowdStrikeArguments = ( + commandName: string, + parameters: RunScriptActionRequestBody['parameters'] +): string => { + // Map each parameter to the required syntax and join them with spaces + // In short: this function has to transform the parameters object into a string that can be used as a CS command + // One word commands eg. 'ls' can go as it is, but if there are more elements eg. 'ls -l', they have to be wrapped in triple backticks + const commandParts = Object.entries(parameters).map(([key, value]) => { + // Check and process the parameter value + let sanitizedValue; + if (typeof value === 'string') { + if (/^```.*```$/.test(value)) { + // If already wrapped in triple backticks, leave unchanged + sanitizedValue = value; + } else { + const strippedValue = value.trim(); // Remove spaces at the beginning and end + if (strippedValue.split(/\s+/).length === 1) { + // If it's a single element (no spaces), use it as-is + sanitizedValue = strippedValue; + } else { + // If it contains multiple elements (spaces), wrap in ``` + sanitizedValue = `\`\`\`${strippedValue}\`\`\``; + } + } + } else { + sanitizedValue = value; + } + return `--${upperFirst(key)}=${sanitizedValue}`; + }); + + // Combine the base command with the constructed parameters + return `${commandName} ${commandParts.join(' ')}`; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/mocks.ts b/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/mocks.ts index 6360ceba71cef..00b4774d9489c 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/mocks.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/endpoint/services/actions/clients/mocks.ts @@ -248,7 +248,7 @@ const createRunScriptOptionsMock = ( const options: RunScriptActionRequestBody = { ...createNoParamsResponseActionOptionsMock(), parameters: { - Raw: 'ls', + raw: 'ls', }, }; return merge(options, overrides); diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/README.md b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/README.md index f159a2c5b2480..b60033b731778 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/README.md +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/README.md @@ -172,5 +172,5 @@ To test out the functionality of large lists with rules, the user will need to i * First, set the appropriate env var in order to enable exceptions features`export ELASTIC_XPACK_SECURITY_SOLUTION_LISTS_FEATURE=true` and `export ELASTIC_XPACK_SECURITY_SOLUTION_EXCEPTIONS_LISTS=true` and start kibana * Second, import a list of ips from a file called `ci-badguys.txt`. The command should look like this: -`cd $HOME/kibana/x-pack/plugins/lists/server/scripts && ./import_list_items_by_filename.sh ip ~/ci-badguys.txt` +`cd $HOME/kibana/x-pack/solutions/security/plugins/lists/server/scripts && ./import_list_items_by_filename.sh ip ~/ci-badguys.txt` * Then, from the detection engine scripts folder (`cd kibana/x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/scripts`) run `./post_rule.sh rules/queries/lists/query_with_list_plugin.json` diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts index 86ac7d136d221..b7cacea3c3757 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts @@ -17,6 +17,18 @@ import type { DataViewsService } from '@kbn/data-views-plugin/common'; import type { AppClient } from '../../..'; import type { EntityStoreConfig } from './types'; import { mockGlobalState } from '../../../../public/common/mock'; +import type { EntityDefinition } from '@kbn/entities-schema'; +import { getUnitedEntityDefinition } from './united_entity_definitions'; + +const unitedDefinition = getUnitedEntityDefinition({ + entityType: 'host', + namespace: 'test', + fieldHistoryLength: 10, + indexPatterns: [], + syncDelay: '1m', + frequency: '1m', +}); +const definition: EntityDefinition = unitedDefinition.entityManagerDefinition; describe('EntityStoreDataClient', () => { const mockSavedObjectClient = savedObjectsClientMock.create(); @@ -182,4 +194,137 @@ describe('EntityStoreDataClient', () => { expect(response.records[0]).toEqual(fakeEntityRecord); }); }); + + describe('getComponentFromEntityDefinition', () => { + it('returns installed false if no definition is provided', () => { + const result = dataClient.getComponentFromEntityDefinition('security_host_test', undefined); + expect(result).toEqual([ + { + id: 'security_host_test', + installed: false, + resource: 'entity_definition', + }, + ]); + }); + + it('returns correct components for EntityDefinitionWithState', () => { + const definitionWithState = { + ...definition, + state: { + installed: true, + running: true, + components: { + transforms: [ + { + id: 'transforms_id', + installed: true, + running: true, + }, + ], + ingestPipelines: [ + { + id: 'pipeline-1', + installed: true, + }, + ], + indexTemplates: [ + { + id: 'indexTemplates_id', + installed: true, + }, + ], + }, + }, + }; + + const result = dataClient.getComponentFromEntityDefinition( + 'security_host_test', + definitionWithState + ); + expect(result).toEqual([ + { + id: 'security_host_test', + installed: true, + resource: 'entity_definition', + }, + { + id: 'security_host_test', + resource: 'transform', + installed: true, + health: 'unknown', + errors: undefined, + }, + { + resource: 'ingest_pipeline', + id: 'pipeline-1', + installed: true, + }, + { + id: 'security_host_test', + installed: true, + resource: 'index_template', + }, + ]); + }); + + it('returns empty array for EntityDefinition without state', () => { + const result = dataClient.getComponentFromEntityDefinition('security_host_test', definition); + expect(result).toEqual([]); + }); + + it('handles transform health issues correctly', () => { + const definitionWithState = { + ...definition, + state: { + installed: true, + components: { + transforms: [ + { + installed: true, + stats: { + health: { + status: 'yellow', + issues: [ + { + type: 'issue-type', + issue: 'issue-message', + details: 'issue-details', + count: 1, + }, + ], + }, + }, + }, + ], + ingestPipelines: [], + indexTemplates: [], + }, + }, + }; + + const result = dataClient.getComponentFromEntityDefinition( + 'security_host_test', + definitionWithState + ); + expect(result).toEqual([ + { + id: 'security_host_test', + installed: true, + resource: 'entity_definition', + }, + { + id: 'security_host_test', + resource: 'transform', + installed: true, + health: 'yellow', + errors: [ + { + title: 'issue-message', + message: 'issue-details', + }, + ], + }, + ]); + }); + }); }); diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts index c18dc1863a8d1..faf2edc154192 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts @@ -15,7 +15,7 @@ import type { AnalyticsServiceSetup, } from '@kbn/core/server'; import { EntityClient } from '@kbn/entityManager-plugin/server/lib/entity_client'; -import type { SortOrder } from '@elastic/elasticsearch/lib/api/types'; +import type { HealthStatus, SortOrder } from '@elastic/elasticsearch/lib/api/types'; import type { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; import type { DataViewsService } from '@kbn/data-views-plugin/common'; import { isEqual } from 'lodash/fp'; @@ -465,7 +465,7 @@ export class EntityStoreDataClient { public getComponentFromEntityDefinition( id: string, - definition: EntityDefinitionWithState | EntityDefinition + definition: EntityDefinitionWithState | EntityDefinition | undefined ): EngineComponentStatus[] { if (!definition) { return [ @@ -478,16 +478,22 @@ export class EntityStoreDataClient { } if ('state' in definition) { + const transformHealthToComponentHealth = ( + health: HealthStatus | undefined + ): EngineComponentStatus['health'] => + health ? (health.toLowerCase() as Lowercase) : 'unknown'; + return [ { id: definition.id, installed: definition.state.installed, resource: EngineComponentResourceEnum.entity_definition, }, - ...definition.state.components.transforms.map(({ installed, running, stats }) => ({ + ...definition.state.components.transforms.map(({ installed, stats }) => ({ id, resource: EngineComponentResourceEnum.transform, installed, + health: transformHealthToComponentHealth(stats?.health?.status), errors: (stats?.health as TransformHealth)?.issues?.map(({ issue, details }) => ({ title: issue, message: details, diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/graph.ts b/x-pack/test/api_integration/apis/cloud_security_posture/graph.ts index 4ff483bff343d..4823c500a3588 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/graph.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/graph.ts @@ -40,7 +40,7 @@ export default function (providerContext: FtrProviderContext) { it('should return 404 when feature flag is not toggled', async () => { await postGraph(supertest, { query: { - eventIds: [], + originEventIds: [], start: 'now-1d/d', end: 'now/d', }, diff --git a/x-pack/test/api_integration/apis/upgrade_assistant/es_deprecation_logs.helpers.ts b/x-pack/test/api_integration/apis/upgrade_assistant/es_deprecation_logs.helpers.ts index 59077c9ac2167..ec2454fdea143 100644 --- a/x-pack/test/api_integration/apis/upgrade_assistant/es_deprecation_logs.helpers.ts +++ b/x-pack/test/api_integration/apis/upgrade_assistant/es_deprecation_logs.helpers.ts @@ -18,7 +18,7 @@ const CHARS_POOL = 'abcdefghijklmnopqrstuvwxyz'; const getRandomString = () => `${chance.string({ pool: CHARS_POOL })}-${Date.now()}`; const deprecationMock = { - 'event.dataset': 'deprecation.elasticsearch', + 'event.dataset': 'elasticsearch.deprecation', '@timestamp': '2021-12-06T16:28:11,104Z', 'log.level': 'CRITICAL', 'log.logger': @@ -30,7 +30,7 @@ const deprecationMock = { message: '[types removal] Specifying include_type_name in get index template requests is deprecated.', 'data_stream.type': 'logs', - 'data_stream.dataset': 'deprecation.elasticsearch', + 'data_stream.dataset': 'elasticsearch.deprecation', 'data_stream.namespace': 'default', 'ecs.version': '1.7', 'elasticsearch.event.category': 'types', diff --git a/x-pack/test/cloud_security_posture_api/config.ts b/x-pack/test/cloud_security_posture_api/config.ts index 4e0ecd1f26e43..212abc50fc9ae 100644 --- a/x-pack/test/cloud_security_posture_api/config.ts +++ b/x-pack/test/cloud_security_posture_api/config.ts @@ -5,7 +5,7 @@ * 2.0. */ import { resolve } from 'path'; -import type { FtrConfigProviderContext } from '@kbn/test'; +import { getKibanaCliLoggers, type FtrConfigProviderContext } from '@kbn/test'; import { CLOUD_SECURITY_PLUGIN_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { @@ -21,6 +21,14 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...xPackAPITestsConfig.get('kbnTestServer'), serverArgs: [ ...xPackAPITestsConfig.get('kbnTestServer.serverArgs'), + `--logging.loggers=${JSON.stringify([ + ...getKibanaCliLoggers(xPackAPITestsConfig.get('kbnTestServer.serverArgs')), + { + name: 'plugins.cloudSecurityPosture', + level: 'all', + appenders: ['default'], + }, + ])}`, /** * Package version is fixed (not latest) so FTR won't suddenly break when package is changed. * diff --git a/x-pack/test/cloud_security_posture_api/routes/graph.ts b/x-pack/test/cloud_security_posture_api/routes/graph.ts index 08adf73839ea2..e2be81a7d40e5 100644 --- a/x-pack/test/cloud_security_posture_api/routes/graph.ts +++ b/x-pack/test/cloud_security_posture_api/routes/graph.ts @@ -48,7 +48,7 @@ export default function (providerContext: FtrProviderContext) { supertestWithoutAuth, { query: { - eventIds: [], + originEventIds: [], start: 'now-1d/d', end: 'now/d', }, @@ -88,7 +88,7 @@ export default function (providerContext: FtrProviderContext) { it('should return 400 when missing `esQuery` field is not of type bool', async () => { await postGraph(supertest, { query: { - eventIds: [], + originEventIds: [], start: 'now-1d/d', end: 'now/d', esQuery: { @@ -102,7 +102,7 @@ export default function (providerContext: FtrProviderContext) { it('should return 400 with unsupported `esQuery`', async () => { await postGraph(supertest, { query: { - eventIds: [], + originEventIds: [], start: 'now-1d/d', end: 'now/d', esQuery: { @@ -122,7 +122,7 @@ export default function (providerContext: FtrProviderContext) { it('should return an empty graph / should return 200 when missing `esQuery` field', async () => { const response = await postGraph(supertest, { query: { - eventIds: [], + originEventIds: [], start: 'now-1d/d', end: 'now/d', }, @@ -136,7 +136,7 @@ export default function (providerContext: FtrProviderContext) { it('should return a graph with nodes and edges by actor', async () => { const response = await postGraph(supertest, { query: { - eventIds: [], + originEventIds: [], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', esQuery: { @@ -177,7 +177,7 @@ export default function (providerContext: FtrProviderContext) { it('should return a graph with nodes and edges by alert', async () => { const response = await postGraph(supertest, { query: { - eventIds: ['kabcd1234efgh5678'], + originEventIds: [{ id: 'kabcd1234efgh5678', isAlert: true }], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', }, @@ -204,10 +204,40 @@ export default function (providerContext: FtrProviderContext) { }); }); + it('should return a graph with nodes and edges by origin event', async () => { + const response = await postGraph(supertest, { + query: { + originEventIds: [{ id: 'kabcd1234efgh5678', isAlert: false }], + start: '2024-09-01T00:00:00Z', + end: '2024-09-02T00:00:00Z', + }, + }).expect(result(200)); + + expect(response.body).to.have.property('nodes').length(3); + expect(response.body).to.have.property('edges').length(2); + expect(response.body).not.to.have.property('messages'); + + response.body.nodes.forEach((node: any) => { + expect(node).to.have.property('color'); + expect(node.color).equal( + 'primary', + `node color mismatched [node: ${node.id}] [actual: ${node.color}]` + ); + }); + + response.body.edges.forEach((edge: any) => { + expect(edge).to.have.property('color'); + expect(edge.color).equal( + 'primary', + `edge color mismatched [edge: ${edge.id}] [actual: ${edge.color}]` + ); + }); + }); + it('color of alert of failed event should be danger', async () => { const response = await postGraph(supertest, { query: { - eventIds: ['failed-event'], + originEventIds: [{ id: 'failed-event', isAlert: true }], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', }, @@ -237,7 +267,7 @@ export default function (providerContext: FtrProviderContext) { it('color of event of failed event should be warning', async () => { const response = await postGraph(supertest, { query: { - eventIds: [], + originEventIds: [], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', esQuery: { @@ -279,7 +309,7 @@ export default function (providerContext: FtrProviderContext) { it('2 grouped events, 1 failed, 1 success', async () => { const response = await postGraph(supertest, { query: { - eventIds: [], + originEventIds: [], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', esQuery: { @@ -327,7 +357,10 @@ export default function (providerContext: FtrProviderContext) { it('should support more than 1 eventIds', async () => { const response = await postGraph(supertest, { query: { - eventIds: ['kabcd1234efgh5678', 'failed-event'], + originEventIds: [ + { id: 'kabcd1234efgh5678', isAlert: true }, + { id: 'failed-event', isAlert: true }, + ], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', }, @@ -357,7 +390,7 @@ export default function (providerContext: FtrProviderContext) { it('should return a graph with nodes and edges by alert and actor', async () => { const response = await postGraph(supertest, { query: { - eventIds: ['kabcd1234efgh5678'], + originEventIds: [{ id: 'kabcd1234efgh5678', isAlert: true }], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', esQuery: { @@ -402,7 +435,7 @@ export default function (providerContext: FtrProviderContext) { it('should filter unknown targets', async () => { const response = await postGraph(supertest, { query: { - eventIds: [], + originEventIds: [], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', esQuery: { @@ -428,7 +461,7 @@ export default function (providerContext: FtrProviderContext) { const response = await postGraph(supertest, { showUnknownTarget: true, query: { - eventIds: [], + originEventIds: [], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', esQuery: { @@ -454,7 +487,7 @@ export default function (providerContext: FtrProviderContext) { const response = await postGraph(supertest, { nodesLimit: 1, query: { - eventIds: [], + originEventIds: [], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', esQuery: { @@ -480,7 +513,7 @@ export default function (providerContext: FtrProviderContext) { it('should support date math', async () => { const response = await postGraph(supertest, { query: { - eventIds: ['kabcd1234efgh5678'], + originEventIds: [{ id: 'kabcd1234efgh5678', isAlert: true }], start: '2024-09-01T12:30:00.000Z||-30m', end: '2024-09-01T12:30:00.000Z||+30m', }, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts index 5583842ca9449..dcc0cebc32ca3 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts @@ -240,7 +240,7 @@ describe( // user can proceed with custom rule editing cy.get(MODAL_CONFIRMATION_BTN) - .should('have.text', `Edit ${existedRulesRows.length} custom rules`) + .should('have.text', `Edit ${existedRulesRows.length} rules`) .click(); // action should finish diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts index 855c4e17afe04..7f313793866ad 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts @@ -127,7 +127,7 @@ describe('Export rules', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] // proceed with exporting only custom rules cy.get(MODAL_CONFIRMATION_BTN) - .should('have.text', `Export ${expectedNumberCustomRulesToBeExported} custom rule`) + .should('have.text', `Export ${expectedNumberCustomRulesToBeExported} rule`) .click(); getAvailablePrebuiltRulesCount().then((availablePrebuiltRulesCount) => { @@ -175,7 +175,7 @@ describe('Export rules', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] // should display correct number of custom rules when one of them has exceptions cy.get(MODAL_CONFIRMATION_BTN) - .should('have.text', `Export ${expectedNumberCustomRulesToBeExported} custom rules`) + .should('have.text', `Export ${expectedNumberCustomRulesToBeExported} rules`) .click(); cy.get(TOASTER_BODY).should( diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/rules_bulk_actions.ts b/x-pack/test/security_solution_cypress/cypress/tasks/rules_bulk_actions.ts index c551054fbc6c7..501989f6c5b69 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/rules_bulk_actions.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/rules_bulk_actions.ts @@ -417,20 +417,20 @@ export const checkPrebuiltRulesCannotBeModified = (rulesCount: number) => { export const checkMachineLearningRulesCannotBeModified = (rulesCount: number) => { cy.get(MODAL_CONFIRMATION_BODY).contains( - `${rulesCount} custom machine learning rule (these rules don't have index patterns)` + `${rulesCount} machine learning rule (these rules don't have index patterns)` ); }; export const checkEsqlRulesCannotBeModified = (rulesCount: number) => { cy.get(MODAL_CONFIRMATION_BODY).contains( - `${rulesCount} custom ES|QL rule (these rules don't have index patterns)` + `${rulesCount} ES|QL rule (these rules don't have index patterns)` ); }; -export const waitForMixedRulesBulkEditModal = (customRulesCount: number) => { +export const waitForMixedRulesBulkEditModal = (rulesCount: number) => { cy.get(MODAL_CONFIRMATION_TITLE).should( 'have.text', - `This action can only be applied to ${customRulesCount} custom rules` + `This action can only be applied to ${rulesCount} rules` ); }; @@ -445,7 +445,7 @@ export const scheduleManualRuleRunForSelectedRules = ( if (disabledCount > 0) { cy.get(BULK_MANUAL_RULE_RUN_WARNING_MODAL).should( 'have.text', - `This action can only be applied to ${enabledCount} custom rulesThis action can't be applied to the following rules in your selection:${disabledCount} rules (Cannot schedule manual rule run for disabled rules)CancelSchedule ${enabledCount} custom rules` + `This action can only be applied to ${enabledCount} rulesThis action can't be applied to the following rules in your selection:${disabledCount} rules (Cannot schedule manual rule run for disabled rules)CancelSchedule ${enabledCount} rules` ); cy.get(CONFIRM_MANUAL_RULE_RUN_WARNING_BTN).click(); } diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/graph.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/graph.ts index aaccdd0e9a41c..2cbe40e945492 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/graph.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/graph.ts @@ -49,7 +49,7 @@ export default function ({ getService }: FtrProviderContext) { it('should return an empty graph', async () => { const response = await postGraph(supertestViewer, { query: { - eventIds: [], + originEventIds: [], start: 'now-1d/d', end: 'now/d', }, @@ -63,7 +63,7 @@ export default function ({ getService }: FtrProviderContext) { it('should return a graph with nodes and edges by actor', async () => { const response = await postGraph(supertestViewer, { query: { - eventIds: [], + originEventIds: [], start: '2024-09-01T00:00:00Z', end: '2024-09-02T00:00:00Z', esQuery: { diff --git a/yarn.lock b/yarn.lock index cb74c18e9410c..ffcd2cad7a861 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6137,7 +6137,7 @@ version "0.0.0" uid "" -"@kbn/lists-plugin@link:x-pack/plugins/lists": +"@kbn/lists-plugin@link:x-pack/solutions/security/plugins/lists": version "0.0.0" uid "" @@ -6953,7 +6953,7 @@ version "0.0.0" uid "" -"@kbn/screenshotting-plugin@link:x-pack/plugins/screenshotting": +"@kbn/screenshotting-plugin@link:x-pack/platform/plugins/shared/screenshotting": version "0.0.0" uid "" @@ -7129,7 +7129,7 @@ version "0.0.0" uid "" -"@kbn/securitysolution-autocomplete@link:packages/kbn-securitysolution-autocomplete": +"@kbn/securitysolution-autocomplete@link:x-pack/solutions/security/packages/kbn-securitysolution-autocomplete": version "0.0.0" uid "" @@ -7141,71 +7141,71 @@ version "0.0.0" uid "" -"@kbn/securitysolution-endpoint-exceptions-common@link:packages/kbn-securitysolution-endpoint-exceptions-common": +"@kbn/securitysolution-endpoint-exceptions-common@link:x-pack/solutions/security/packages/kbn-securitysolution-endpoint-exceptions-common": version "0.0.0" uid "" -"@kbn/securitysolution-es-utils@link:packages/kbn-securitysolution-es-utils": +"@kbn/securitysolution-es-utils@link:src/platform/packages/shared/kbn-securitysolution-es-utils": version "0.0.0" uid "" -"@kbn/securitysolution-exception-list-components@link:packages/kbn-securitysolution-exception-list-components": +"@kbn/securitysolution-exception-list-components@link:x-pack/solutions/security/packages/kbn-securitysolution-exception-list-components": version "0.0.0" uid "" -"@kbn/securitysolution-exceptions-common@link:packages/kbn-securitysolution-exceptions-common": +"@kbn/securitysolution-exceptions-common@link:x-pack/solutions/security/packages/kbn-securitysolution-exceptions-common": version "0.0.0" uid "" -"@kbn/securitysolution-hook-utils@link:packages/kbn-securitysolution-hook-utils": +"@kbn/securitysolution-hook-utils@link:x-pack/solutions/security/packages/kbn-securitysolution-hook-utils": version "0.0.0" uid "" -"@kbn/securitysolution-io-ts-alerting-types@link:packages/kbn-securitysolution-io-ts-alerting-types": +"@kbn/securitysolution-io-ts-alerting-types@link:x-pack/solutions/security/packages/kbn-securitysolution-io-ts-alerting-types": version "0.0.0" uid "" -"@kbn/securitysolution-io-ts-list-types@link:packages/kbn-securitysolution-io-ts-list-types": +"@kbn/securitysolution-io-ts-list-types@link:x-pack/solutions/security/packages/kbn-securitysolution-io-ts-list-types": version "0.0.0" uid "" -"@kbn/securitysolution-io-ts-types@link:packages/kbn-securitysolution-io-ts-types": +"@kbn/securitysolution-io-ts-types@link:src/platform/packages/shared/kbn-securitysolution-io-ts-types": version "0.0.0" uid "" -"@kbn/securitysolution-io-ts-utils@link:packages/kbn-securitysolution-io-ts-utils": +"@kbn/securitysolution-io-ts-utils@link:src/platform/packages/shared/kbn-securitysolution-io-ts-utils": version "0.0.0" uid "" -"@kbn/securitysolution-list-api@link:packages/kbn-securitysolution-list-api": +"@kbn/securitysolution-list-api@link:x-pack/solutions/security/packages/kbn-securitysolution-list-api": version "0.0.0" uid "" -"@kbn/securitysolution-list-constants@link:packages/kbn-securitysolution-list-constants": +"@kbn/securitysolution-list-constants@link:x-pack/solutions/security/packages/kbn-securitysolution-list-constants": version "0.0.0" uid "" -"@kbn/securitysolution-list-hooks@link:packages/kbn-securitysolution-list-hooks": +"@kbn/securitysolution-list-hooks@link:x-pack/solutions/security/packages/kbn-securitysolution-list-hooks": version "0.0.0" uid "" -"@kbn/securitysolution-list-utils@link:packages/kbn-securitysolution-list-utils": +"@kbn/securitysolution-list-utils@link:x-pack/solutions/security/packages/kbn-securitysolution-list-utils": version "0.0.0" uid "" -"@kbn/securitysolution-lists-common@link:packages/kbn-securitysolution-lists-common": +"@kbn/securitysolution-lists-common@link:x-pack/solutions/security/packages/kbn-securitysolution-lists-common": version "0.0.0" uid "" -"@kbn/securitysolution-rules@link:packages/kbn-securitysolution-rules": +"@kbn/securitysolution-rules@link:src/platform/packages/shared/kbn-securitysolution-rules": version "0.0.0" uid "" -"@kbn/securitysolution-t-grid@link:packages/kbn-securitysolution-t-grid": +"@kbn/securitysolution-t-grid@link:x-pack/solutions/security/packages/kbn-securitysolution-t-grid": version "0.0.0" uid "" -"@kbn/securitysolution-utils@link:packages/kbn-securitysolution-utils": +"@kbn/securitysolution-utils@link:x-pack/solutions/security/packages/kbn-securitysolution-utils": version "0.0.0" uid ""