From 8042faf448436859e8d591871ad343552b1dbeea Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Mon, 7 Nov 2022 13:55:56 +0100 Subject: [PATCH 1/7] Remove dependencies for empty @types/* packages (#144324) (#144686) The removed packages were empty becuase the packages for which they provide types now ship with their own types. So they are no longer needed. The following command was run to find them: find node_modules/@types \ -mindepth 1 \ -maxdepth 1 \ -type d '!' \ -exec test -e "{}/index.d.ts" ';' \ -print In this case that produced the following output: node_modules/@types/moment-timezone node_modules/@types/strip-ansi node_modules/@types/joi node_modules/@types/rrule node_modules/@types/vfile-message node_modules/@types/reduce-reducers node_modules/@types/react-resize-detector node_modules/@types/pretty-ms Except for `vfile-message` all of these were direct dependencies and could be removed. (cherry picked from commit b02d976a3b8466ae4e0b1ec9840175dce1790719) # Conflicts: # packages/core/logging/core-logging-common-internal/BUILD.bazel # packages/kbn-failed-test-reporter-cli/BUILD.bazel # yarn.lock Co-authored-by: Spencer --- package.json | 7 -- .../BUILD.bazel | 2 +- .../core-logging-server-internal/BUILD.bazel | 2 +- .../logging/core-logging-server/BUILD.bazel | 2 +- .../BUILD.bazel | 2 +- packages/kbn-analytics/BUILD.bazel | 2 +- packages/kbn-config-schema/BUILD.bazel | 2 +- packages/kbn-es-query/BUILD.bazel | 2 +- packages/kbn-server-http-tools/BUILD.bazel | 1 - packages/kbn-test-jest-helpers/BUILD.bazel | 2 +- packages/kbn-test/BUILD.bazel | 2 +- yarn.lock | 95 +++---------------- 12 files changed, 24 insertions(+), 97 deletions(-) diff --git a/package.json b/package.json index a6ca187983f6d..578cbbb846b64 100644 --- a/package.json +++ b/package.json @@ -817,7 +817,6 @@ "@types/intl-relativeformat": "^2.1.0", "@types/jest": "^26.0.22", "@types/jest-axe": "^3.5.3", - "@types/joi": "^17.2.3", "@types/jquery": "^3.3.31", "@types/js-levenshtein": "^1.1.0", "@types/js-search": "^1.4.0", @@ -1149,7 +1148,6 @@ "@types/mocha": "^9.1.1", "@types/mock-fs": "^4.13.1", "@types/moment-duration-format": "^2.2.3", - "@types/moment-timezone": "^0.5.30", "@types/mustache": "^0.8.31", "@types/nock": "^10.0.3", "@types/node": "16.11.41", @@ -1167,7 +1165,6 @@ "@types/pixelmatch": "^5.2.4", "@types/pngjs": "^3.4.0", "@types/prettier": "^2.3.2", - "@types/pretty-ms": "^5.0.0", "@types/prop-types": "^15.7.5", "@types/rbush": "^3.0.0", "@types/react": "^17.0.45", @@ -1176,7 +1173,6 @@ "@types/react-grid-layout": "^1.3.2", "@types/react-intl": "^2.3.15", "@types/react-is": "^17.0.3", - "@types/react-resize-detector": "^6.1.0", "@types/react-router": "^5.1.7", "@types/react-router-config": "^5.0.2", "@types/react-router-dom": "^5.1.5", @@ -1184,11 +1180,9 @@ "@types/react-virtualized": "^9.21.21", "@types/react-vis": "^1.11.9", "@types/recompose": "^0.30.10", - "@types/reduce-reducers": "^1.0.0", "@types/redux-actions": "^2.6.1", "@types/redux-logger": "^3.0.8", "@types/resolve": "^1.20.1", - "@types/rrule": "^2.2.9", "@types/seedrandom": ">=2.0.0 <4.0.0", "@types/selenium-webdriver": "^4.1.5", "@types/semver": "^7", @@ -1197,7 +1191,6 @@ "@types/sinon": "^7.0.13", "@types/source-map-support": "^0.5.3", "@types/stats-lite": "^2.2.0", - "@types/strip-ansi": "^5.2.1", "@types/styled-components": "^5.1.0", "@types/supertest": "^2.0.5", "@types/tapable": "^1.0.6", diff --git a/packages/core/integrations/core-integrations-browser-internal/BUILD.bazel b/packages/core/integrations/core-integrations-browser-internal/BUILD.bazel index 73df7f69b705a..871489cd2dc60 100644 --- a/packages/core/integrations/core-integrations-browser-internal/BUILD.bazel +++ b/packages/core/integrations/core-integrations-browser-internal/BUILD.bazel @@ -46,7 +46,7 @@ RUNTIME_DEPS = [ TYPES_DEPS = [ "@npm//@types/node", "@npm//@types/jest", - "@npm//@types/moment-timezone", + "@npm//moment-timezone", "@npm//rxjs", "//packages/core/base/core-base-browser-internal:npm_module_types", "//packages/core/ui-settings/core-ui-settings-browser:npm_module_types", diff --git a/packages/core/logging/core-logging-server-internal/BUILD.bazel b/packages/core/logging/core-logging-server-internal/BUILD.bazel index fbc3cc6626eec..7b0383dd66071 100644 --- a/packages/core/logging/core-logging-server-internal/BUILD.bazel +++ b/packages/core/logging/core-logging-server-internal/BUILD.bazel @@ -48,7 +48,7 @@ TYPES_DEPS = [ "@npm//@types/jest", "@npm//@types/lodash", "@npm//rxjs", - "@npm//@types/moment-timezone", + "@npm//moment-timezone", "@npm//elastic-apm-node", "//packages/kbn-safer-lodash-set:npm_module_types", "//packages/kbn-logging:npm_module_types", diff --git a/packages/core/logging/core-logging-server/BUILD.bazel b/packages/core/logging/core-logging-server/BUILD.bazel index c575f538904de..4a1ed983bdcf6 100644 --- a/packages/core/logging/core-logging-server/BUILD.bazel +++ b/packages/core/logging/core-logging-server/BUILD.bazel @@ -40,7 +40,7 @@ RUNTIME_DEPS = [ TYPES_DEPS = [ "@npm//@types/node", "@npm//@types/jest", - "@npm//@types/moment-timezone", + "@npm//moment-timezone", "@npm//rxjs", "//packages/kbn-logging:npm_module_types", "//packages/kbn-config-schema:npm_module_types" diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/BUILD.bazel b/packages/core/ui-settings/core-ui-settings-server-internal/BUILD.bazel index ae77747b313e3..ca07c8795b8f0 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/BUILD.bazel +++ b/packages/core/ui-settings/core-ui-settings-server-internal/BUILD.bazel @@ -49,7 +49,7 @@ TYPES_DEPS = [ "@npm//@types/node", "@npm//@types/jest", "@npm//@types/semver", - "@npm//@types/moment-timezone", + "@npm//moment-timezone", "@npm//lodash", "//packages/kbn-ui-shared-deps-npm:npm_module_types", "//packages/kbn-logging:npm_module_types", diff --git a/packages/kbn-analytics/BUILD.bazel b/packages/kbn-analytics/BUILD.bazel index 4c9065c836068..ff4ac0d232c2f 100644 --- a/packages/kbn-analytics/BUILD.bazel +++ b/packages/kbn-analytics/BUILD.bazel @@ -43,7 +43,7 @@ RUNTIME_DEPS = [ TYPES_DEPS = [ "@npm//moment", - "@npm//@types/moment-timezone", + "@npm//moment-timezone", "@npm//@types/node", ] diff --git a/packages/kbn-config-schema/BUILD.bazel b/packages/kbn-config-schema/BUILD.bazel index aebd34efa2f08..24d9254d4e369 100644 --- a/packages/kbn-config-schema/BUILD.bazel +++ b/packages/kbn-config-schema/BUILD.bazel @@ -48,7 +48,7 @@ TYPES_DEPS = [ "@npm//moment", "@npm//tsd", "@npm//@types/jest", - "@npm//@types/joi", + "@npm//joi", "@npm//@types/lodash", "@npm//@types/node", "@npm//@types/type-detect", diff --git a/packages/kbn-es-query/BUILD.bazel b/packages/kbn-es-query/BUILD.bazel index 2a7c445c32aac..0b192feea64ab 100644 --- a/packages/kbn-es-query/BUILD.bazel +++ b/packages/kbn-es-query/BUILD.bazel @@ -55,7 +55,7 @@ TYPES_DEPS = [ "@npm//tslib", "@npm//@types/jest", "@npm//@types/lodash", - "@npm//@types/moment-timezone", + "@npm//moment-timezone", "@npm//@types/node", ] diff --git a/packages/kbn-server-http-tools/BUILD.bazel b/packages/kbn-server-http-tools/BUILD.bazel index 5c73a34ffe5e7..a07ceb69639c7 100644 --- a/packages/kbn-server-http-tools/BUILD.bazel +++ b/packages/kbn-server-http-tools/BUILD.bazel @@ -56,7 +56,6 @@ TYPES_DEPS = [ "@npm//moment", "@npm//@types/hapi__hapi", "@npm//@types/jest", - "@npm//@types/joi", "@npm//@types/node", "@npm//@types/uuid", ] diff --git a/packages/kbn-test-jest-helpers/BUILD.bazel b/packages/kbn-test-jest-helpers/BUILD.bazel index d31f9184cf2ac..c783aa5b0fa4b 100644 --- a/packages/kbn-test-jest-helpers/BUILD.bazel +++ b/packages/kbn-test-jest-helpers/BUILD.bazel @@ -107,7 +107,7 @@ TYPES_DEPS = [ "@npm//@types/history", "@npm//@types/jest", "@npm//@types/jest-axe", - "@npm//@types/joi", + "@npm//joi", "@npm//@types/lodash", "@npm//@types/mustache", "@npm//@types/normalize-path", diff --git a/packages/kbn-test/BUILD.bazel b/packages/kbn-test/BUILD.bazel index a51766a8f6c63..7656bc38d408c 100644 --- a/packages/kbn-test/BUILD.bazel +++ b/packages/kbn-test/BUILD.bazel @@ -125,7 +125,7 @@ TYPES_DEPS = [ "@npm//@types/history", "@npm//@types/jest", "@npm//@types/js-yaml", - "@npm//@types/joi", + "@npm//joi", "@npm//@types/lodash", "@npm//@types/minimatch", "@npm//@types/mustache", diff --git a/yarn.lock b/yarn.lock index f99deaefec9af..a095733d7215b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6686,13 +6686,6 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/joi@^17.2.3": - version "17.2.3" - resolved "https://registry.yarnpkg.com/@types/joi/-/joi-17.2.3.tgz#b7768ed9d84f1ebd393328b9f97c1cf3d2b94798" - integrity sha512-dGjs/lhrWOa+eO0HwgxCSnDm5eMGCsXuvLglMghJq32F6q5LyyNuXb41DHzrg501CKNOSSAHmfB7FDGeUnDmzw== - dependencies: - joi "*" - "@types/jquery@*", "@types/jquery@^3.3.31": version "3.3.31" resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.31.tgz#27c706e4bf488474e1cb54a71d8303f37c93451b" @@ -8143,13 +8136,6 @@ dependencies: moment ">=2.14.0" -"@types/moment-timezone@^0.5.30": - version "0.5.30" - resolved "https://registry.yarnpkg.com/@types/moment-timezone/-/moment-timezone-0.5.30.tgz#340ed45fe3e715f4a011f5cfceb7cb52aad46fc7" - integrity sha512-aDVfCsjYnAQaV/E9Qc24C5Njx1CoDjXsEgkxtp9NyXDpYu4CCbmclb6QhWloS9UTU/8YROUEEdEkWI0D7DxnKg== - dependencies: - moment-timezone "*" - "@types/mustache@^0.8.31": version "0.8.31" resolved "https://registry.yarnpkg.com/@types/mustache/-/mustache-0.8.31.tgz#7c86cbf74f7733f9e3bdc28817623927eb386616" @@ -8308,13 +8294,6 @@ resolved "https://registry.yarnpkg.com/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz#72a26101dc567b0d68fd956cf42314556e42d601" integrity sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ== -"@types/pretty-ms@^5.0.0": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@types/pretty-ms/-/pretty-ms-5.0.1.tgz#f2f0d7be58caf8613d149053d446e0282ae11ff3" - integrity sha512-FFR4uj0p47Yq6JCrOt7DCaiUJIw7t9Vh7wwt3bF6qq99QRqjSH/doEGZsIIgZqhDmwjBObVBkrn0ICm1pY+mPg== - dependencies: - pretty-ms "*" - "@types/prismjs@*": version "1.16.3" resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.16.3.tgz#73ae78b3e339777a1a1b7a8df89dcd6b8fe750c5" @@ -8413,13 +8392,6 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-resize-detector@^6.1.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@types/react-resize-detector/-/react-resize-detector-6.1.0.tgz#a90fcd74728dacbec6bd4d948af64f6e107ac611" - integrity sha512-runvF8/keQK3ipyjb7Ez2RKtaOZgrpqEN2PVCp93B/WavgFEeogFMnplMu4OuhpQHwpcu9UbqFiT2cPWoCWmWQ== - dependencies: - react-resize-detector "*" - "@types/react-router-config@^5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@types/react-router-config/-/react-router-config-5.0.2.tgz#4d3b52e71ed363a1976a12321e67b09a99ad6d10" @@ -8512,13 +8484,6 @@ dependencies: "@types/react" "*" -"@types/reduce-reducers@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/reduce-reducers/-/reduce-reducers-1.0.0.tgz#033120b109159f4b344210ee75310d1ec3fcc8ef" - integrity sha512-MWKF9QDH/HaMQZvGyQlrut1ttyrFVIrGZqhCXPBcl5LelhnfC7dIE2jK2qZjxFHUCeXgjKCk5hN+/GzA7GgqjQ== - dependencies: - reduce-reducers "*" - "@types/redux-actions@^2.6.1": version "2.6.1" resolved "https://registry.yarnpkg.com/@types/redux-actions/-/redux-actions-2.6.1.tgz#0940e97fa35ad3004316bddb391d8e01d2efa605" @@ -8560,13 +8525,6 @@ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== -"@types/rrule@^2.2.9": - version "2.2.9" - resolved "https://registry.yarnpkg.com/@types/rrule/-/rrule-2.2.9.tgz#b25222b5057b9a9e6eea28ce9e94673a957c960f" - integrity sha512-OWTezBoGwsL2nn9SFbLbiTrAic1hpxAIRqeF8QDB84iW6KBEAHM6Oj9T2BEokgeIDgT1q73sfD0gI1S2yElSFA== - dependencies: - rrule "*" - "@types/scheduler@*": version "0.16.2" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" @@ -8660,13 +8618,6 @@ resolved "https://registry.yarnpkg.com/@types/stats-lite/-/stats-lite-2.2.0.tgz#bc8190bf9dfa1e16b89eaa2b433c99dff0804de9" integrity sha512-YV6SS4QC+pbzqjMIV8qVSTDOOazgKBLTVaN+7PfuxELjz/eyzc20KwDVGPrbHt2OcYMA7K2ezLB45Cp6DpNOSQ== -"@types/strip-ansi@^5.2.1": - version "5.2.1" - resolved "https://registry.yarnpkg.com/@types/strip-ansi/-/strip-ansi-5.2.1.tgz#acd97f1f091e332bb7ce697c4609eb2370fa2a92" - integrity sha512-1l5iM0LBkVU8JXxnIoBqNvg+yyOXxPeN6DNoD+7A9AN1B8FhYPSeIXgyNqwIqg1uzipTgVC2hmuDzB0u9qw/PA== - dependencies: - strip-ansi "*" - "@types/styled-components@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.0.tgz#24d3412ba5395aa06e14fbc93c52f9454cebd0d6" @@ -18357,7 +18308,7 @@ jest@^26.6.3: import-local "^3.0.2" jest-cli "^26.6.3" -joi@*, joi@^17.3.0, joi@^17.4.0: +joi@^17.3.0, joi@^17.4.0: version "17.4.0" resolved "https://registry.yarnpkg.com/joi/-/joi-17.4.0.tgz#b5c2277c8519e016316e49ababd41a1908d9ef20" integrity sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg== @@ -20250,7 +20201,7 @@ moment-duration-format@^2.3.2: resolved "https://registry.yarnpkg.com/moment-duration-format/-/moment-duration-format-2.3.2.tgz#5fa2b19b941b8d277122ff3f87a12895ec0d6212" integrity sha512-cBMXjSW+fjOb4tyaVHuaVE/A5TqkukDWiOfxxAjY+PEqmmBQlLwn+8OzwPiG3brouXKY5Un4pBjAeB6UToXHaQ== -moment-timezone@*, moment-timezone@^0.5.34: +moment-timezone@^0.5.34: version "0.5.34" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.34.tgz#a75938f7476b88f155d3504a9343f7519d9a405c" integrity sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg== @@ -22410,13 +22361,6 @@ pretty-hrtime@^1.0.3: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= -pretty-ms@*: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-7.0.0.tgz#45781273110caf35f55cab21a8a9bd403a233dc0" - integrity sha512-J3aPWiC5e9ZeZFuSeBraGxSkGMOvulSWsxDByOcbD1Pr75YL3LSNIKIb52WXbCLE1sS5s4inBBbryjF4Y05Ceg== - dependencies: - parse-ms "^2.1.0" - pretty-ms@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-6.0.0.tgz#39a0eb5f31d359bcee43c9579e6ddf4a02a82ff0" @@ -23267,7 +23211,7 @@ react-resizable@^3.0.4: prop-types "15.x" react-draggable "^4.0.3" -react-resize-detector@*, react-resize-detector@^7.1.1: +react-resize-detector@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-7.1.1.tgz#18d5b84909d5ab13abe0a68ddf0fb8e80c553dfc" integrity sha512-rU54VTstNzFLZAmMNHqt8xINjDWP7SQR05A2HUW0OGvl4vcrXzgaxrrqAY5tZMfkLkoYm5u0i0qGqCjdc2jyAA== @@ -23692,16 +23636,16 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -reduce-reducers@*, reduce-reducers@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-1.0.4.tgz#fb77e751a9eb0201760ac5a605ca8c9c2d0537f8" - integrity sha512-Mb2WZ2bJF597exiqX7owBzrqJ74DHLK3yOQjCyPAaNifRncE8OD0wFIuoMhXxTnHK07+8zZ2SJEKy/qtiyR7vw== - reduce-reducers@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.4.3.tgz#8e052618801cd8fc2714b4915adaa8937eb6d66c" integrity sha512-+CNMnI8QhgVMtAt54uQs3kUxC3Sybpa7Y63HR14uGLgI9/QR5ggHvpxwhGGe3wmx5V91YwqQIblN9k5lspAmGw== +reduce-reducers@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-1.0.4.tgz#fb77e751a9eb0201760ac5a605ca8c9c2d0537f8" + integrity sha512-Mb2WZ2bJF597exiqX7owBzrqJ74DHLK3yOQjCyPAaNifRncE8OD0wFIuoMhXxTnHK07+8zZ2SJEKy/qtiyR7vw== + redux-actions@^2.6.5: version "2.6.5" resolved "https://registry.yarnpkg.com/redux-actions/-/redux-actions-2.6.5.tgz#bdca548768ee99832a63910c276def85e821a27e" @@ -24362,15 +24306,6 @@ robust-predicates@^3.0.0: resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a" integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g== -rrule@*: - version "2.6.9" - resolved "https://registry.yarnpkg.com/rrule/-/rrule-2.6.9.tgz#8ee4ee261451e84852741f92ded769245580744a" - integrity sha512-PE4ErZDMfAcRnc1B35bZgPGS9mbn7Z9bKDgk6+XgrIwvBjeWk7JVEYsqKwHYTrDGzsHPtZTpaon8IyeKzAhj5w== - dependencies: - tslib "^1.10.0" - optionalDependencies: - luxon "^1.21.3" - rrule@2.6.4: version "2.6.4" resolved "https://registry.yarnpkg.com/rrule/-/rrule-2.6.4.tgz#7f4f31fda12bc7249bb176c891109a9bc448e035" @@ -25726,13 +25661,6 @@ stringify-entities@^3.0.0, stringify-entities@^3.0.1: is-decimal "^1.0.2" is-hexadecimal "^1.0.0" -strip-ansi@*, strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@5.2.0, strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -25754,6 +25682,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-bom-string@1.X: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" From 2d398059183694c7953b4406d8038cb0e9c9ce03 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 7 Nov 2022 08:36:37 -0500 Subject: [PATCH 2/7] Update dependency xml-crypto to ^3.0.1 (#144682) (#144693) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> (cherry picked from commit 9c6c725147ed27aa69614c005dc46a25e0eddba1) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 578cbbb846b64..a3bc6ea14254c 100644 --- a/package.json +++ b/package.json @@ -1396,7 +1396,7 @@ "webpack-dev-server": "^4.9.3", "webpack-merge": "^4.2.2", "webpack-sources": "^1.4.1", - "xml-crypto": "^3.0.0", + "xml-crypto": "^3.0.1", "xmlbuilder": "13.0.2", "yargs": "^15.4.1" } diff --git a/yarn.lock b/yarn.lock index a095733d7215b..da0cf31a1a946 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9203,10 +9203,10 @@ object.fromentries "^2.0.0" prop-types "^15.7.0" -"@xmldom/xmldom@^0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.3.tgz#beaf980612532aa9a3004aff7e428943aeaa0711" - integrity sha512-Lv2vySXypg4nfa51LY1nU8yDAGo/5YwF+EY/rUZgIbfvwVARcd67ttCM8SMsTeJy51YhHYavEq+FS6R0hW9PFQ== +"@xmldom/xmldom@^0.8.5": + version "0.8.6" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.6.tgz#8a1524eb5bd5e965c1e3735476f0262469f71440" + integrity sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg== "@xobotyi/scrollbar-width@1.9.5": version "1.9.5" @@ -28444,12 +28444,12 @@ xdg-basedir@^4.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== -xml-crypto@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-crypto/-/xml-crypto-3.0.0.tgz#e3342f9c9a94455d4700431ac9803493bf51cf81" - integrity sha512-vdmZOsWgjnFxYGY7OwCgxs+HLWzwvLgX2n0NSYWh3gudckQyNOmtJTT6ooOWEvDZSpC9qRjRs2bEXqKFi1oCHw== +xml-crypto@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/xml-crypto/-/xml-crypto-3.0.1.tgz#1d4852b040e80413d8058e2917eddd9f17a00b8b" + integrity sha512-7XrwB3ujd95KCO6+u9fidb8ajvRJvIfGNWD0XLJoTWlBKz+tFpUzEYxsN+Il/6/gHtEs1RgRh2RH+TzhcWBZUw== dependencies: - "@xmldom/xmldom" "^0.8.3" + "@xmldom/xmldom" "^0.8.5" xpath "0.0.32" xml-name-validator@^3.0.0: From 6be94d5698ad2efa24865a31fa768f920ac1b8b2 Mon Sep 17 00:00:00 2001 From: Pablo Machado Date: Mon, 7 Nov 2022 16:26:30 +0100 Subject: [PATCH 3/7] [8.5] Fix Incorrect alerts are displayed in timeline when navigating from Detection & Responses page (#144319) (#144675) * Fix Incorrect alerts are displayed in timeline when navigating from Detection & Responses page (#144319) * Fix Incorrect alerts are displayed in the timeline when navigating from Detection & Responses page (cherry picked from commit 10dc2c6f7815fa7688402abe3363aa495e6fc38c) # Conflicts: # x-pack/plugins/security_solution/public/overview/components/detection_response/host_alerts_table/host_alerts_table.tsx # x-pack/plugins/security_solution/public/overview/components/detection_response/rule_alerts_table/rule_alerts_table.tsx # x-pack/plugins/security_solution/public/overview/components/detection_response/user_alerts_table/user_alerts_table.tsx # x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.test.tsx # x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/index.tsx * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * Fix conflicts Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../host_alerts_table.test.tsx | 48 +++++++++++++++++ .../host_alerts_table/host_alerts_table.tsx | 30 +++++++++-- .../rule_alerts_table.test.tsx | 36 ++++++++++++- .../rule_alerts_table/rule_alerts_table.tsx | 19 +++++-- .../user_alerts_table.test.tsx | 51 ++++++++++++++++++- .../user_alerts_table/user_alerts_table.tsx | 29 +++++++++-- .../components/detection_response/utils.tsx | 2 + 7 files changed, 201 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/host_alerts_table/host_alerts_table.test.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/host_alerts_table/host_alerts_table.test.tsx index e4cabce7780b9..cbd4e0c59b224 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/host_alerts_table/host_alerts_table.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/host_alerts_table/host_alerts_table.test.tsx @@ -13,6 +13,7 @@ import { TestProviders } from '../../../../common/mock'; import { parsedVulnerableHostsAlertsResult } from './mock_data'; import type { UseHostAlertsItems } from './use_host_alerts_items'; import { HostAlertsTable } from './host_alerts_table'; +import { openAlertsFilter } from '../utils'; const mockGetAppUrl = jest.fn(); jest.mock('../../../../common/lib/kibana/hooks', () => { @@ -25,6 +26,15 @@ jest.mock('../../../../common/lib/kibana/hooks', () => { }; }); +const mockOpenTimelineWithFilters = jest.fn(); +jest.mock('../hooks/use_navigate_to_timeline', () => { + return { + useNavigateToTimeline: () => ({ + openTimelineWithFilters: mockOpenTimelineWithFilters, + }), + }; +}); + type UseHostAlertsItemsReturn = ReturnType; const defaultUseHostAlertsItemsReturn: UseHostAlertsItemsReturn = { items: [], @@ -124,4 +134,42 @@ describe('HostAlertsTable', () => { fireEvent.click(page3); expect(mockSetPage).toHaveBeenCalledWith(2); }); + + it('should open timeline with filters when total alerts is clicked', () => { + mockUseHostAlertsItemsReturn({ items: [parsedVulnerableHostsAlertsResult[0]] }); + const { getByTestId } = renderComponent(); + + fireEvent.click(getByTestId('hostSeverityAlertsTable-totalAlertsLink')); + + expect(mockOpenTimelineWithFilters).toHaveBeenCalledWith([ + [ + { + field: 'host.name', + value: 'Host-342m5gl1g2', + }, + openAlertsFilter, + ], + ]); + }); + + it('should open timeline with filters when critical alert count is clicked', () => { + mockUseHostAlertsItemsReturn({ items: [parsedVulnerableHostsAlertsResult[0]] }); + const { getByTestId } = renderComponent(); + + fireEvent.click(getByTestId('hostSeverityAlertsTable-criticalLink')); + + expect(mockOpenTimelineWithFilters).toHaveBeenCalledWith([ + [ + { + field: 'host.name', + value: 'Host-342m5gl1g2', + }, + openAlertsFilter, + { + field: 'kibana.alert.severity', + value: 'critical', + }, + ], + ]); + }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/host_alerts_table/host_alerts_table.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/host_alerts_table/host_alerts_table.tsx index b5ec1de73fa39..95cd3e2fd2dd3 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/host_alerts_table/host_alerts_table.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/host_alerts_table/host_alerts_table.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React, { useMemo, useCallback } from 'react'; import type { EuiBasicTableColumn } from '@elastic/eui'; import { @@ -28,7 +28,7 @@ import { HostDetailsLink } from '../../../../common/components/links'; import { useQueryToggle } from '../../../../common/containers/query_toggle'; import { useNavigateToTimeline } from '../hooks/use_navigate_to_timeline'; import * as i18n from '../translations'; -import { ITEMS_PER_PAGE, SEVERITY_COLOR } from '../utils'; +import { ITEMS_PER_PAGE, openAlertsFilter, SEVERITY_COLOR } from '../utils'; import type { HostAlertsItem } from './use_host_alerts_items'; import { useHostAlertsItems } from './use_host_alerts_items'; @@ -43,7 +43,24 @@ type GetTableColumns = ( const DETECTION_RESPONSE_HOST_SEVERITY_QUERY_ID = 'vulnerableHostsBySeverityQuery'; export const HostAlertsTable = React.memo(({ signalIndexName }: HostAlertsTableProps) => { - const { openHostInTimeline } = useNavigateToTimeline(); + const { openTimelineWithFilters } = useNavigateToTimeline(); + + const openHostInTimeline = useCallback( + ({ hostName, severity }: { hostName: string; severity?: string }) => { + const hostNameFilter = { field: 'host.name', value: hostName }; + const severityFilter = severity + ? { field: 'kibana.alert.severity', value: severity } + : undefined; + + openTimelineWithFilters( + severityFilter + ? [[hostNameFilter, openAlertsFilter, severityFilter]] + : [[hostNameFilter, openAlertsFilter]] + ); + }, + [openTimelineWithFilters] + ); + const { toggleStatus, setToggleStatus } = useQueryToggle( DETECTION_RESPONSE_HOST_SEVERITY_QUERY_ID ); @@ -118,7 +135,11 @@ const getTableColumns: GetTableColumns = (handleClick) => [ name: i18n.ALERTS_TEXT, 'data-test-subj': 'hostSeverityAlertsTable-totalAlerts', render: (totalAlerts: number, { hostName }) => ( - handleClick({ hostName })}> + handleClick({ hostName })} + > ), @@ -129,6 +150,7 @@ const getTableColumns: GetTableColumns = (handleClick) => [ render: (count: number, { hostName }) => ( handleClick({ hostName, severity: 'critical' })} > diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/rule_alerts_table/rule_alerts_table.test.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/rule_alerts_table/rule_alerts_table.test.tsx index 0776b69e96b27..fca9b4cd8e479 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/rule_alerts_table/rule_alerts_table.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/rule_alerts_table/rule_alerts_table.test.tsx @@ -8,13 +8,14 @@ import moment from 'moment'; import React from 'react'; -import { render } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; import { SecurityPageName } from '../../../../../common/constants'; import { TestProviders } from '../../../../common/mock'; import type { RuleAlertsTableProps } from './rule_alerts_table'; import { RuleAlertsTable } from './rule_alerts_table'; import type { RuleAlertsItem, UseRuleAlertsItems } from './use_rule_alerts_items'; +import { openAlertsFilter } from '../utils'; const mockGetAppUrl = jest.fn(); jest.mock('../../../../common/lib/kibana/hooks', () => { @@ -27,6 +28,15 @@ jest.mock('../../../../common/lib/kibana/hooks', () => { }; }); +const mockOpenTimelineWithFilters = jest.fn(); +jest.mock('../hooks/use_navigate_to_timeline', () => { + return { + useNavigateToTimeline: () => ({ + openTimelineWithFilters: mockOpenTimelineWithFilters, + }), + }; +}); + type UseRuleAlertsItemsReturn = ReturnType; const defaultUseRuleAlertsItemsReturn: UseRuleAlertsItemsReturn = { items: [], @@ -44,10 +54,11 @@ jest.mock('./use_rule_alerts_items', () => ({ const defaultProps: RuleAlertsTableProps = { signalIndexName: '', }; +const ruleName = 'ruleName'; const items: RuleAlertsItem[] = [ { id: 'ruleId', - name: 'ruleName', + name: ruleName, last_alert_at: moment().subtract(1, 'day').format(), alert_count: 10, severity: 'high', @@ -144,4 +155,25 @@ describe('RuleAlertsTable', () => { expect(result.getByTestId('severityRuleAlertsTable-name')).toHaveAttribute('href', linkUrl); }); + + it('should open timeline with filters when total alerts is clicked', () => { + mockUseRuleAlertsItemsReturn({ items }); + const { getByTestId } = render( + + + + ); + + fireEvent.click(getByTestId('severityRuleAlertsTable-alertCountLink')); + + expect(mockOpenTimelineWithFilters).toHaveBeenCalledWith([ + [ + { + field: 'kibana.alert.rule.name', + value: ruleName, + }, + openAlertsFilter, + ], + ]); + }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/rule_alerts_table/rule_alerts_table.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/rule_alerts_table/rule_alerts_table.tsx index 59a92896ddb85..82ec2837e77b7 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/rule_alerts_table/rule_alerts_table.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/rule_alerts_table/rule_alerts_table.tsx @@ -22,7 +22,7 @@ import { FormattedRelative } from '@kbn/i18n-react'; import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; import { HeaderSection } from '../../../../common/components/header_section'; -import { SEVERITY_COLOR } from '../utils'; +import { openAlertsFilter, SEVERITY_COLOR } from '../utils'; import * as i18n from '../translations'; import type { RuleAlertsItem } from './use_rule_alerts_items'; import { useRuleAlertsItems } from './use_rule_alerts_items'; @@ -90,7 +90,11 @@ export const getTableColumns: GetTableColumns = ({ getAppUrl, navigateTo, openRu name: i18n.RULE_ALERTS_COLUMN_ALERT_COUNT, 'data-test-subj': 'severityRuleAlertsTable-alertCount', render: (alertCount: number, { name }) => ( - openRuleInTimeline(name)}> + openRuleInTimeline(name)} + > ), @@ -114,7 +118,16 @@ export const RuleAlertsTable = React.memo(({ signalIndexNa skip: !toggleStatus, }); - const { openRuleInTimeline } = useNavigateToTimeline(); + const { openTimelineWithFilters } = useNavigateToTimeline(); + + const openRuleInTimeline = useCallback( + (ruleName: string) => { + openTimelineWithFilters([ + [{ field: 'kibana.alert.rule.name', value: ruleName }, openAlertsFilter], + ]); + }, + [openTimelineWithFilters] + ); const navigateToAlerts = useCallback(() => { navigateTo({ deepLinkId: SecurityPageName.alerts }); diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/user_alerts_table/user_alerts_table.test.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/user_alerts_table/user_alerts_table.test.tsx index 9b6ed807e34e6..1d7cb38b864ac 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/user_alerts_table/user_alerts_table.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/user_alerts_table/user_alerts_table.test.tsx @@ -13,7 +13,9 @@ import { TestProviders } from '../../../../common/mock'; import { parsedVulnerableUserAlertsResult } from './mock_data'; import type { UseUserAlertsItems } from './use_user_alerts_items'; import { UserAlertsTable } from './user_alerts_table'; +import { openAlertsFilter } from '../utils'; +const userName = 'crffn20qcs'; const mockGetAppUrl = jest.fn(); jest.mock('../../../../common/lib/kibana/hooks', () => { const original = jest.requireActual('../../../../common/lib/kibana/hooks'); @@ -25,6 +27,15 @@ jest.mock('../../../../common/lib/kibana/hooks', () => { }; }); +const mockOpenTimelineWithFilters = jest.fn(); +jest.mock('../hooks/use_navigate_to_timeline', () => { + return { + useNavigateToTimeline: () => ({ + openTimelineWithFilters: mockOpenTimelineWithFilters, + }), + }; +}); + type UseUserAlertsItemsReturn = ReturnType; const defaultUseUserAlertsItemsReturn: UseUserAlertsItemsReturn = { items: [], @@ -98,7 +109,7 @@ describe('UserAlertsTable', () => { mockUseUserAlertsItemsReturn({ items: [parsedVulnerableUserAlertsResult[0]] }); const { queryByTestId } = renderComponent(); - expect(queryByTestId('userSeverityAlertsTable-userName')).toHaveTextContent('crffn20qcs'); + expect(queryByTestId('userSeverityAlertsTable-userName')).toHaveTextContent(userName); expect(queryByTestId('userSeverityAlertsTable-totalAlerts')).toHaveTextContent('4'); expect(queryByTestId('userSeverityAlertsTable-critical')).toHaveTextContent('4'); expect(queryByTestId('userSeverityAlertsTable-high')).toHaveTextContent('1'); @@ -124,4 +135,42 @@ describe('UserAlertsTable', () => { fireEvent.click(page3); expect(mockSetPage).toHaveBeenCalledWith(2); }); + + it('should open timeline with filters when total alerts is clicked', () => { + mockUseUserAlertsItemsReturn({ items: [parsedVulnerableUserAlertsResult[0]] }); + const { getByTestId } = renderComponent(); + + fireEvent.click(getByTestId('userSeverityAlertsTable-totalAlertsLink')); + + expect(mockOpenTimelineWithFilters).toHaveBeenCalledWith([ + [ + { + field: 'user.name', + value: userName, + }, + openAlertsFilter, + ], + ]); + }); + + it('should open timeline with filters when critical alerts link is clicked', () => { + mockUseUserAlertsItemsReturn({ items: [parsedVulnerableUserAlertsResult[0]] }); + const { getByTestId } = renderComponent(); + + fireEvent.click(getByTestId('userSeverityAlertsTable-criticalLink')); + + expect(mockOpenTimelineWithFilters).toHaveBeenCalledWith([ + [ + { + field: 'user.name', + value: userName, + }, + openAlertsFilter, + { + field: 'kibana.alert.severity', + value: 'critical', + }, + ], + ]); + }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/user_alerts_table/user_alerts_table.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/user_alerts_table/user_alerts_table.tsx index c50f5976360ed..0e1c1ad5407b9 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/user_alerts_table/user_alerts_table.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/user_alerts_table/user_alerts_table.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React, { useMemo, useCallback } from 'react'; import type { EuiBasicTableColumn } from '@elastic/eui'; import { @@ -28,7 +28,7 @@ import { UserDetailsLink } from '../../../../common/components/links'; import { useQueryToggle } from '../../../../common/containers/query_toggle'; import { useNavigateToTimeline } from '../hooks/use_navigate_to_timeline'; import * as i18n from '../translations'; -import { ITEMS_PER_PAGE, SEVERITY_COLOR } from '../utils'; +import { ITEMS_PER_PAGE, openAlertsFilter, SEVERITY_COLOR } from '../utils'; import type { UserAlertsItem } from './use_user_alerts_items'; import { useUserAlertsItems } from './use_user_alerts_items'; @@ -43,7 +43,23 @@ type GetTableColumns = ( const DETECTION_RESPONSE_USER_SEVERITY_QUERY_ID = 'vulnerableUsersBySeverityQuery'; export const UserAlertsTable = React.memo(({ signalIndexName }: UserAlertsTableProps) => { - const { openUserInTimeline } = useNavigateToTimeline(); + const { openTimelineWithFilters } = useNavigateToTimeline(); + + const openUserInTimeline = useCallback( + ({ userName, severity }: { userName: string; severity?: string }) => { + const userNameFilter = { field: 'user.name', value: userName }; + const severityFilter = severity + ? { field: 'kibana.alert.severity', value: severity } + : undefined; + + openTimelineWithFilters( + severityFilter + ? [[userNameFilter, openAlertsFilter, severityFilter]] + : [[userNameFilter, openAlertsFilter]] + ); + }, + [openTimelineWithFilters] + ); const { toggleStatus, setToggleStatus } = useQueryToggle( DETECTION_RESPONSE_USER_SEVERITY_QUERY_ID ); @@ -118,7 +134,11 @@ const getTableColumns: GetTableColumns = (handleClick) => [ name: i18n.ALERTS_TEXT, 'data-test-subj': 'userSeverityAlertsTable-totalAlerts', render: (totalAlerts: number, { userName }) => ( - handleClick({ userName })}> + handleClick({ userName })} + > ), @@ -129,6 +149,7 @@ const getTableColumns: GetTableColumns = (handleClick) => [ render: (count: number, { userName }) => ( handleClick({ userName, severity: 'critical' })} > diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/utils.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/utils.tsx index 76b690e0fbf0a..b82108c50e0e2 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/utils.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/utils.tsx @@ -21,3 +21,5 @@ const MAX_ALLOWED_RESULTS = 100; * */ export const getPageCount = (count: number = 0) => Math.ceil(Math.min(count || 0, MAX_ALLOWED_RESULTS) / ITEMS_PER_PAGE); + +export const openAlertsFilter = { field: 'kibana.alert.workflow_status', value: 'open' }; From a36af933d884aa5cbd688cb5326c9c147f1761a4 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 7 Nov 2022 12:30:13 -0500 Subject: [PATCH 4/7] [DOCS] Improves examples in KQL doc (#144072) (#144727) * [DOCS] Improves examples in KQL doc * Update docs/concepts/kuery.asciidoc Co-authored-by: Lukas Olson Co-authored-by: Lukas Olson (cherry picked from commit 5e7989844de566316e51fb48e09ca1dfdfa01f4a) Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> --- docs/concepts/kuery.asciidoc | 302 ++++++++++------------------------- 1 file changed, 81 insertions(+), 221 deletions(-) diff --git a/docs/concepts/kuery.asciidoc b/docs/concepts/kuery.asciidoc index a7d2e83717411..4e8b6bc4043e0 100644 --- a/docs/concepts/kuery.asciidoc +++ b/docs/concepts/kuery.asciidoc @@ -1,326 +1,186 @@ [[kuery-query]] -=== Kibana Query Language +=== {kib} Query Language -The Kibana Query Language (KQL) is a simple syntax for filtering {es} data using -free text search or field-based search. KQL is only used for filtering data, and has -no role in sorting or aggregating the data. +The {kib} Query Language (KQL) is a simple text-based query language for filtering data. -KQL is able to suggest field names, values, and operators as you type. -The performance of the suggestions is controlled by <>. +* KQL only filters data, and has no role in aggregating, transforming, or sorting data. +* KQL is not to be confused with the <>, which has a different feature set. -KQL has a different set of features than the <>. KQL is able to query -nested fields and <>. KQL does not support regular expressions -or searching with fuzzy terms. +Use KQL to filter documents where a value for a field exists, matches a given value, or is within a given range. [discrete] -=== Terms query +=== Filter for documents where a field exists -A terms query uses *exact search terms*. Spaces separate each search term, and only one term -is required to match the document. Use quotation marks to indicate a *phrase match*. - -To query using *exact search terms*, enter the field name followed by `:` and -then the values separated by spaces: - -[source,yaml] -------------------- -http.response.status_code:400 401 404 -------------------- - -For text fields, this will match any value regardless of order: +To filter documents for which an indexed value exists for a given field, use the `*` operator. +For example, to filter for documents where the `http.request.method` field exists, use the following syntax: [source,yaml] ------------------- -http.response.body.content.text:quick brown fox +http.request.method: * ------------------- -To query for an *exact phrase*, use quotation marks around the values: - -[source,yaml] -------------------- -http.response.body.content.text:"quick brown fox" -------------------- - -Field names are not required by KQL. When a field name is not provided, terms -will be matched by the default fields in your index settings. To search across fields: - -[source,yaml] -------------------- -"quick brown fox" -------------------- +This checks for any indexed value, including an empty string. [discrete] -=== Boolean queries +=== Filter for documents that match a value -KQL supports `or`, `and`, and `not`. By default, `and` has a higher precedence than `or`. -To override the default precedence, group operators in parentheses. These operators can -be upper or lower case. - -To match documents where response is `200`, extension is `php`, or both: - -[source,yaml] -------------------- -response:200 or extension:php -------------------- - -To match documents where response is `200` and extension is `php`: +Use KQL to filter for documents that match a specific number, text, date, or boolean value. +For example, to filter for documents where the `http.request.method` is GET, use the following query: [source,yaml] ------------------- -response:200 and extension:php +http.request.method: GET ------------------- -To match documents where response is `200` or `404`. +The field parameter is optional. If not provided, all fields are searched for the given value. +For example, to search all fields for “Hello”, use the following: [source,yaml] ------------------- -response:(200 or 404) +Hello ------------------- -To match documents where response is `200` and extension is either `php` or `css`: +When querying keyword, numeric, date, or boolean fields, the value must be an exact match, +including punctuation and case. However, when querying text fields, {es} analyzes the +value provided according to the {ref}/analysis.html[field’s mapping settings]. +For example, to search for documents where `http.request.body.content` (a `text` field) +contains the text “null pointer”: [source,yaml] ------------------- -response:200 and (extension:php or extension:css) +http.request.body.content: null pointer ------------------- -To match documents where `response` is 200 and `extension` is -`php` or extension is `css`, and response is anything: +Because this is a `text` field, the order of these search terms does not matter, and +even documents containing “pointer null” are returned. To search `text` fields where the +terms are in the order provided, surround the value in quotation marks, as follows: [source,yaml] ------------------- -response:200 and extension:php or extension:css +http.request.body.content: "null pointer" ------------------- -To match documents where response is not `200`: +Certain characters must be escaped by a backslash (unless surrounded by quotes). +For example, to search for documents where `http.request.referrer` is https://example.com, +use either of the following queries: [source,yaml] ------------------- -not response:200 +http.request.referrer: "https://example.com" +http.request.referrer: https\://example.com ------------------- -To match documents where response is `200` but extension is not `php` or `css`. +You must escape following characters: [source,yaml] ------------------- -response:200 and not (extension:php or extension:css) -------------------- - -To match multi-value fields that contain a list of terms: - -[source,yaml] -------------------- -tags:(success and info and security) +\():<>"* ------------------- [discrete] -=== Range queries +=== Filter for documents within a range -KQL supports `>`, `>=`, `<`, and `<=` on numeric and date types. +To search documents that contain terms within a provided range, use KQL’s range syntax. +For example, to search for all documents for which `http.response.bytes` is less than 10000, +use the following syntax: [source,yaml] ------------------- -account_number >= 100 and items_sold <= 200 +http.response.bytes < 10000 ------------------- -[discrete] -=== Date range queries - -Typically, Kibana's <> is sufficient for setting a time range, -but in some cases you might need to search on dates. Include the date range in quotes. +To search for an inclusive range, combine multiple range queries. +For example, to search for documents where `http.response.bytes` is greater than 10000 +but less than or equal to 20000, use the following syntax: [source,yaml] ------------------- -@timestamp < "2021-01-02T21:55:59" +http.response.bytes > 10000 and http.response.bytes <= 20000 ------------------- -[source,yaml] -------------------- -@timestamp < "2021-01" -------------------- +You can also use range syntax for string values, IP addresses, and timestamps. +For example, to search for documents earlier than two weeks ago, use the following syntax: [source,yaml] ------------------- -@timestamp < "2021" +@timestamp < now-2w ------------------- -KQL supports date math expressions. - -[source,yaml] -------------------- -@timestamp < now-1d -------------------- - -[source,yaml] -------------------- -updated_at > 2022-02-17||+1M/d -------------------- - -Check the -{ref}/common-options.html#date-math[date math documentation] for more examples. +For more examples on acceptable date formats, refer to {ref}/common-options.html#date-math[Date Math]. [discrete] -=== Exist queries +=== Filter for documents using wildcards -An exist query matches documents that contain any value for a field, in this case, -response: +To search for documents matching a pattern, use the wildcard syntax. +For example, to find documents where `http.response.status_code` begins with a 4, use the following syntax: [source,yaml] ------------------- -response:* +http.response.status_code: 4* ------------------- -Existence is defined by {es} and includes all values, including empty text. - -[discrete] -=== Wildcard queries +By default, leading wildcards are not allowed for performance reasons. +You can modify this with the <> advanced setting. -Wildcards queries can be used to *search by a term prefix* or to *search multiple fields*. -The default settings of {kib} *prevent leading wildcards* for performance reasons, -but this can be allowed with an <>. +NOTE: Only `*` is currently supported. This matches zero or more characters. -To match documents where `machine.os` starts with `win`, such -as "windows 7" and "windows 10": - -[source,yaml] -------------------- -machine.os:win* -------------------- +[discrete] +=== Negating a query -To match multiple fields: +To negate or exclude a set of documents, use the `not` keyword (not case-sensitive). +For example, to filter documents where the `http.request.method` is *not* GET, use the following query: [source,yaml] ------------------- -machine.os*:windows 10 +NOT http.request.method: GET ------------------- -This syntax is handy when you have text and keyword -versions of a field. The query checks machine.os and machine.os.keyword -for the term -`windows 10`. - - [discrete] -=== Nested field queries - -A main consideration for querying {ref}/nested.html[nested fields] is how to -match parts of the nested query to the individual nested documents. -You can: - -* *Match parts of the query to a single nested document only.* This is what most users want when querying on a nested field. -* *Match parts of the query to different nested documents.* This is how a regular object field works. - This query is generally less useful than matching to a single document. - -In the following document, `items` is a nested field. Each document in the nested -field contains a name, stock, and category. - -[source,json] ----------------------------------- -{ - "grocery_name": "Elastic Eats", - "items": [ - { - "name": "banana", - "stock": "12", - "category": "fruit" - }, - { - "name": "peach", - "stock": "10", - "category": "fruit" - }, - { - "name": "carrot", - "stock": "9", - "category": "vegetable" - }, - { - "name": "broccoli", - "stock": "5", - "category": "vegetable" - } - ] -} ----------------------------------- +=== Combining multiple queries -[discrete] -==== Match a single document - -To match stores that have more than 10 bananas in stock: +To combine multiple queries, use the `and`/`or` keywords (not case-sensitive). +For example, to find documents where the `http.request.method` is GET *or* the `http.response.status_code` is 400, +use the following query: [source,yaml] ------------------- -items:{ name:banana and stock > 10 } +http.request.method: GET OR http.response.status_code: 400 ------------------- -`items` is the nested path. Everything inside the curly braces (the nested group) -must match a single nested document. - -The following query does not return any matches because no single nested -document has bananas with a stock of 9. +Similarly, to find documents where the `http.request.method` is GET *and* the +`http.response.status_code` is 400, use this query: [source,yaml] ------------------- -items:{ name:banana and stock:9 } +http.request.method: GET AND http.response.status_code: 400 ------------------- -[discrete] -==== Match different documents - -The following subqueries are in separate nested groups -and can match different nested documents: +To specify precedence when combining multiple queries, use parentheses. +For example, to find documents where the `http.request.method` is GET *and* +the `http.response.status_code` is 200, *or* the `http.request.method` is POST *and* +`http.response.status_code` is 400, use the following: [source,yaml] ------------------- -items:{ name:banana } and items:{ stock:9 } +(http.request.method: GET AND http.response.status_code: 200) OR +(http.request.method: POST AND http.response.status_code: 400) ------------------- -`name:banana` matches the first document in the array and `stock:9` -matches the third document in the array. - -[discrete] -==== Match single and different documents - -To find a store with more than 10 -bananas that *also* stocks vegetables: +You can also use parentheses for shorthand syntax when querying multiple values for the same field. +For example, to find documents where the `http.request.method` is GET, POST, *or* DELETE, use the following: [source,yaml] ------------------- -items:{ name:banana and stock > 10 } and items:{ category:vegetable } +http.request.method: (GET OR POST OR DELETE) ------------------- -The first nested group (`name:banana and stock > 10`) must match a single document, but the `category:vegetables` -subquery can match a different nested document because it is in a separate group. - [discrete] -==== Nested fields inside other nested fields - -KQL supports nested fields inside other nested fields—you have to -specify the full path. In this document, -`level1` and `level2` are nested fields: - -[source,json] ----------------------------------- -{ - "level1": [ - { - "level2": [ - { - "prop1": "foo", - "prop2": "bar" - }, - { - "prop1": "baz", - "prop2": "qux" - } - ] - } - ] -} ----------------------------------- - -To match on a single nested document: +=== Matching multiple fields + +Wildcards can also be used to query multiple fields. For example, to search for +documents where any sub-field of `http.response` contains “error”, use the following: [source,yaml] ------------------- -level1.level2:{ prop1:foo and prop2:bar } +http.response.*: error ------------------- From adf074014b7c9a64c60720ee7791d91d1d9936d7 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Mon, 7 Nov 2022 20:56:01 +0200 Subject: [PATCH 5/7] [Security Solution] Disable ML rule's edit button link under basic license (#143260) (#144723) **Resolves:** [#139796](https://github.com/elastic/kibana/issues/139796) ## Summary It disables ML rule's edit button link under the basic license. ## Details ML rules aren't available under the basic license but installable from the prebuilt rules. Having an active edit button makes the UX inconsistent. Disabling such a button under the basic license for ML rules improves UX though doesn't block a user from opening the rule editing page from the address bar. Before: https://user-images.githubusercontent.com/3775283/195552179-525f0423-3a62-4ab5-b1ef-0f5cafe2286e.mov After: https://user-images.githubusercontent.com/3775283/195551540-b95fabeb-4e50-4a26-ae42-1a72f53573dc.mov ### Checklist - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) (cherry picked from commit a670c7f37651cbccacb9b054b622ad308d3eec8d) # Conflicts: # x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx --- .../common/utils/privileges/index.test.ts | 30 +++++++ .../public/common/utils/privileges/index.ts | 15 +++- .../rules/rule_actions_overflow/index.tsx | 8 +- .../all/bulk_actions/use_bulk_actions.tsx | 40 +++++++--- .../rules/all/exceptions/exceptions_table.tsx | 4 +- .../rules/all/rules_table_actions.tsx | 4 +- .../rules/all/rules_tables.tsx | 4 +- .../rules/all/use_columns.tsx | 36 +++++---- .../detection_engine/rules/create/index.tsx | 10 +-- .../edit_rule_settings_button_link.tsx | 56 +++++++++++++ .../detection_engine/rules/details/index.tsx | 79 +++++++------------ .../detection_engine/rules/edit/index.tsx | 4 +- .../detection_engine/rules/helpers.test.tsx | 24 ------ .../pages/detection_engine/rules/helpers.tsx | 4 - .../pages/detection_engine/rules/index.tsx | 12 +-- .../detection_engine/rules/translations.ts | 11 ++- .../translations/translations/fr-FR.json | 2 +- .../translations/translations/ja-JP.json | 2 +- .../translations/translations/zh-CN.json | 2 +- 19 files changed, 213 insertions(+), 134 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/common/utils/privileges/index.test.ts create mode 100644 x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/components/edit_rule_settings_button_link.tsx diff --git a/x-pack/plugins/security_solution/public/common/utils/privileges/index.test.ts b/x-pack/plugins/security_solution/public/common/utils/privileges/index.test.ts new file mode 100644 index 0000000000000..34abe0dd52c9a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/utils/privileges/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 { hasUserCRUDPermission } from '.'; + +describe('privileges utils', () => { + describe('hasUserCRUDPermission', () => { + test("returns true when user's CRUD operations are null", () => { + const result = hasUserCRUDPermission(null); + + expect(result).toBeTruthy(); + }); + + test('returns false when user cannot CRUD', () => { + const result = hasUserCRUDPermission(false); + + expect(result).toBeFalsy(); + }); + + test('returns true when user can CRUD', () => { + const result = hasUserCRUDPermission(true); + + expect(result).toBeTruthy(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/utils/privileges/index.ts b/x-pack/plugins/security_solution/public/common/utils/privileges/index.ts index de8ad087f27e6..c420630ee23ba 100644 --- a/x-pack/plugins/security_solution/public/common/utils/privileges/index.ts +++ b/x-pack/plugins/security_solution/public/common/utils/privileges/index.ts @@ -6,7 +6,7 @@ */ import type { Rule } from '../../../detections/containers/detection_engine/rules'; -import * as i18n from '../../../detections/pages/detection_engine/rules/translations'; +import * as i18nActions from '../../../detections/pages/detection_engine/rules/translations'; import { isMlRule } from '../../../../common/machine_learning/helpers'; import * as detectionI18n from '../../../detections/pages/detection_engine/translations'; @@ -29,21 +29,28 @@ export const canEditRuleWithActions = ( return true; }; -export const getToolTipContent = ( +// typed as null not undefined as the initial state for this value is null. +export const hasUserCRUDPermission = (canUserCRUD: boolean | null): boolean => + canUserCRUD != null ? canUserCRUD : true; + +export const explainLackOfPermission = ( rule: Rule | null | undefined, hasMlPermissions: boolean, hasReadActionsPrivileges: | boolean | Readonly<{ [x: string]: boolean; - }> + }>, + canUserCRUD: boolean | null ): string | undefined => { if (rule == null) { return undefined; } else if (isMlRule(rule.type) && !hasMlPermissions) { return detectionI18n.ML_RULES_DISABLED_MESSAGE; } else if (!canEditRuleWithActions(rule, hasReadActionsPrivileges)) { - return i18n.EDIT_RULE_SETTINGS_TOOLTIP; + return i18nActions.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES; + } else if (!hasUserCRUDPermission(canUserCRUD)) { + return i18nActions.LACK_OF_KIBANA_SECURITY_PRIVILEGES; } else { return undefined; } diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx index beb8e8365d74e..404319ef75832 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx @@ -23,7 +23,7 @@ import { useBoolState } from '../../../../common/hooks/use_bool_state'; import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; import { useKibana } from '../../../../common/lib/kibana'; -import { getToolTipContent } from '../../../../common/utils/privileges'; +import { canEditRuleWithActions } from '../../../../common/utils/privileges'; import type { Rule } from '../../../containers/detection_engine/rules'; import { executeRulesBulkAction, @@ -96,7 +96,11 @@ const RuleActionsOverflowComponent = ({ > <>{i18nActions.DUPLICATE_RULE} diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx index 17443855a6abf..05dee7d20823b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/use_bulk_actions.tsx @@ -332,7 +332,9 @@ export const useBulkActions = ({ disabled: missingActionPrivileges || containsLoading || (!containsDisabled && !isAllSelected), onClick: handleEnableAction, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -342,7 +344,9 @@ export const useBulkActions = ({ 'data-test-subj': 'duplicateRuleBulk', disabled: isEditDisabled, onClick: handleDuplicateAction, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -366,7 +370,9 @@ export const useBulkActions = ({ 'data-test-subj': 'addRuleActionsBulk', disabled: !hasActionsPrivileges || isEditDisabled, onClick: handleBulkEdit(BulkActionEditType.add_rule_actions), - toolTipContent: !hasActionsPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: !hasActionsPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -376,7 +382,9 @@ export const useBulkActions = ({ 'data-test-subj': 'setScheduleBulk', disabled: isEditDisabled, onClick: handleBulkEdit(BulkActionEditType.set_schedule), - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -386,7 +394,9 @@ export const useBulkActions = ({ 'data-test-subj': 'applyTimelineTemplateBulk', disabled: isEditDisabled, onClick: handleBulkEdit(BulkActionEditType.set_timeline), - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -405,7 +415,9 @@ export const useBulkActions = ({ disabled: missingActionPrivileges || containsLoading || (!containsEnabled && !isAllSelected), onClick: handleDisableActions, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', icon: undefined, }, @@ -439,7 +451,9 @@ export const useBulkActions = ({ 'data-test-subj': 'addTagsBulkEditRule', onClick: handleBulkEdit(BulkActionEditType.add_tags), disabled: isEditDisabled, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', }, { @@ -448,7 +462,9 @@ export const useBulkActions = ({ 'data-test-subj': 'deleteTagsBulkEditRule', onClick: handleBulkEdit(BulkActionEditType.delete_tags), disabled: isEditDisabled, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', }, ], @@ -463,7 +479,9 @@ export const useBulkActions = ({ 'data-test-subj': 'addIndexPatternsBulkEditRule', onClick: handleBulkEdit(BulkActionEditType.add_index_patterns), disabled: isEditDisabled, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', }, { @@ -472,7 +490,9 @@ export const useBulkActions = ({ 'data-test-subj': 'deleteIndexPatternsBulkEditRule', onClick: handleBulkEdit(BulkActionEditType.delete_index_patterns), disabled: isEditDisabled, - toolTipContent: missingActionPrivileges ? i18n.EDIT_RULE_SETTINGS_TOOLTIP : undefined, + toolTipContent: missingActionPrivileges + ? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES + : undefined, toolTipPosition: 'right', }, ], diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx index d7908d0bbce66..98e552b1c174a 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx @@ -19,6 +19,7 @@ import { import type { NamespaceType, ExceptionListFilter } from '@kbn/securitysolution-io-ts-list-types'; import { useApi, useExceptionLists } from '@kbn/securitysolution-list-hooks'; +import { hasUserCRUDPermission } from '../../../../../../common/utils/privileges'; import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; import { AutoDownload } from '../../../../../../common/components/auto_download/auto_download'; import { useKibana } from '../../../../../../common/lib/kibana'; @@ -36,7 +37,6 @@ import { ExceptionsSearchBar } from './exceptions_search_bar'; import { getSearchFilters } from '../helpers'; import { SecurityPageName } from '../../../../../../../common/constants'; import { useUserData } from '../../../../../components/user_info'; -import { userHasPermissions } from '../../helpers'; import { useListsConfig } from '../../../../../containers/detection_engine/lists/use_lists_config'; import type { ExceptionsTableItem } from './types'; import { MissingPrivilegesCallOut } from '../../../../../components/callouts/missing_privileges_callout'; @@ -63,7 +63,7 @@ const exceptionReferenceModalInitialState: ReferenceModalState = { export const ExceptionListsTable = React.memo(() => { const { formatUrl } = useFormatUrl(SecurityPageName.rules); const [{ loading: userInfoLoading, canUserCRUD, canUserREAD }] = useUserData(); - const hasPermissions = userHasPermissions(canUserCRUD); + const hasPermissions = hasUserCRUDPermission(canUserCRUD); const { loading: listsConfigLoading } = useListsConfig(); const loading = userInfoLoading || listsConfigLoading; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx index cfd83c3ab408f..0a10026194869 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_actions.tsx @@ -43,7 +43,7 @@ export const getRulesTableActions = ({ 'data-test-subj': 'editRuleAction', description: i18n.EDIT_RULE_SETTINGS, name: !actionsPrivileges ? ( - + <>{i18n.EDIT_RULE_SETTINGS} ) : ( @@ -59,7 +59,7 @@ export const getRulesTableActions = ({ description: i18n.DUPLICATE_RULE, icon: 'copy', name: !actionsPrivileges ? ( - + <>{i18n.DUPLICATE_RULE} ) : ( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx index 9165bdea5c533..f577a71a6b6e5 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx @@ -179,8 +179,8 @@ export const RulesTables = React.memo( [setPage, setPerPage, setSortingOptions] ); - const rulesColumns = useRulesColumns({ hasPermissions }); - const monitoringColumns = useMonitoringColumns({ hasPermissions }); + const rulesColumns = useRulesColumns({ hasCRUDPermissions: hasPermissions }); + const monitoringColumns = useMonitoringColumns({ hasCRUDPermissions: hasPermissions }); const handleCreatePrePackagedRules = useCallback(async () => { if (createPrePackagedRules != null) { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx index c5032a1eb9b72..2fa479d01b5d2 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx @@ -22,7 +22,10 @@ import { FormattedRelativePreferenceDate } from '../../../../../common/component import { getRuleDetailsTabUrl } from '../../../../../common/components/link_to/redirect_to_detection_engine'; import { PopoverItems } from '../../../../../common/components/popover_items'; import { useKibana, useUiSetting$ } from '../../../../../common/lib/kibana'; -import { canEditRuleWithActions, getToolTipContent } from '../../../../../common/utils/privileges'; +import { + canEditRuleWithActions, + explainLackOfPermission, +} from '../../../../../common/utils/privileges'; import { RuleSwitch } from '../../../../components/rules/rule_switch'; import { SeverityBadge } from '../../../../components/rules/severity_badge'; import type { Rule } from '../../../../containers/detection_engine/rules'; @@ -48,10 +51,10 @@ import { RuleDetailTabs } from '../details'; export type TableColumn = EuiBasicTableColumn | EuiTableActionsColumnType; interface ColumnsProps { - hasPermissions: boolean; + hasCRUDPermissions: boolean; } -const useEnabledColumn = ({ hasPermissions }: ColumnsProps): TableColumn => { +const useEnabledColumn = ({ hasCRUDPermissions }: ColumnsProps): TableColumn => { const hasMlPermissions = useHasMlPermissions(); const hasActionsPrivileges = useHasActionsPrivileges(); const { loadingRulesAction, loadingRuleIds } = useRulesTableContext().state; @@ -68,14 +71,19 @@ const useEnabledColumn = ({ hasPermissions }: ColumnsProps): TableColumn => { render: (_, rule: Rule) => ( { width: '95px', sortable: true, }), - [hasActionsPrivileges, hasMlPermissions, hasPermissions, loadingIds] + [hasActionsPrivileges, hasMlPermissions, hasCRUDPermissions, loadingIds] ); }; @@ -195,9 +203,9 @@ const useActionsColumn = (): EuiTableActionsColumnType => { ); }; -export const useRulesColumns = ({ hasPermissions }: ColumnsProps): TableColumn[] => { +export const useRulesColumns = ({ hasCRUDPermissions }: ColumnsProps): TableColumn[] => { const actionsColumn = useActionsColumn(); - const enabledColumn = useEnabledColumn({ hasPermissions }); + const enabledColumn = useEnabledColumn({ hasCRUDPermissions }); const ruleNameColumn = useRuleNameColumn(); const { isInMemorySorting } = useRulesTableContext().state; const [showRelatedIntegrations] = useUiSetting$(SHOW_RELATED_INTEGRATIONS_SETTING); @@ -292,12 +300,12 @@ export const useRulesColumns = ({ hasPermissions }: ColumnsProps): TableColumn[] width: '65px', }, enabledColumn, - ...(hasPermissions ? [actionsColumn] : []), + ...(hasCRUDPermissions ? [actionsColumn] : []), ], [ actionsColumn, enabledColumn, - hasPermissions, + hasCRUDPermissions, isInMemorySorting, ruleNameColumn, showRelatedIntegrations, @@ -305,10 +313,10 @@ export const useRulesColumns = ({ hasPermissions }: ColumnsProps): TableColumn[] ); }; -export const useMonitoringColumns = ({ hasPermissions }: ColumnsProps): TableColumn[] => { +export const useMonitoringColumns = ({ hasCRUDPermissions }: ColumnsProps): TableColumn[] => { const docLinks = useKibana().services.docLinks; const actionsColumn = useActionsColumn(); - const enabledColumn = useEnabledColumn({ hasPermissions }); + const enabledColumn = useEnabledColumn({ hasCRUDPermissions }); const ruleNameColumn = useRuleNameColumn(); const { isInMemorySorting } = useRulesTableContext().state; const [showRelatedIntegrations] = useUiSetting$(SHOW_RELATED_INTEGRATIONS_SETTING); @@ -425,13 +433,13 @@ export const useMonitoringColumns = ({ hasPermissions }: ColumnsProps): TableCol width: '16%', }, enabledColumn, - ...(hasPermissions ? [actionsColumn] : []), + ...(hasCRUDPermissions ? [actionsColumn] : []), ], [ actionsColumn, docLinks.links.siem.troubleshootGaps, enabledColumn, - hasPermissions, + hasCRUDPermissions, isInMemorySorting, ruleNameColumn, showRelatedIntegrations, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx index 0a4914274d2e6..0ea11725ab27a 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/index.tsx @@ -18,6 +18,7 @@ import React, { useCallback, useRef, useState, useMemo, useEffect } from 'react' import styled from 'styled-components'; import type { DataViewListItem } from '@kbn/data-views-plugin/common'; +import { hasUserCRUDPermission } from '../../../../../common/utils/privileges'; import { isThreatMatchRule } from '../../../../../../common/detection_engine/utils'; import { useCreateRule } from '../../../../containers/detection_engine/rules'; import type { CreateRulesSchema } from '../../../../../../common/detection_engine/schemas/request'; @@ -38,12 +39,7 @@ import { StepAboutRule } from '../../../../components/rules/step_about_rule'; import { StepScheduleRule } from '../../../../components/rules/step_schedule_rule'; import { StepRuleActions } from '../../../../components/rules/step_rule_actions'; import * as RuleI18n from '../translations'; -import { - redirectToDetections, - getActionMessageParams, - userHasPermissions, - MaxWidthEuiFlexItem, -} from '../helpers'; +import { redirectToDetections, getActionMessageParams, MaxWidthEuiFlexItem } from '../helpers'; import type { AboutStepRule, DefineStepRule, @@ -364,7 +360,7 @@ const CreateRulePageComponent: React.FC = () => { path: getDetectionEngineUrl(), }); return null; - } else if (!userHasPermissions(canUserCRUD)) { + } else if (!hasUserCRUDPermission(canUserCRUD)) { navigateToApp(APP_UI_ID, { deepLinkId: SecurityPageName.rules, path: getRulesUrl(), diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/components/edit_rule_settings_button_link.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/components/edit_rule_settings_button_link.tsx new file mode 100644 index 0000000000000..6ef7ebb0cae4c --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/components/edit_rule_settings_button_link.tsx @@ -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 React, { useCallback } from 'react'; +import { EuiToolTip } from '@elastic/eui'; +import { useKibana } from '../../../../../../common/lib/kibana'; +import { SecuritySolutionLinkButton } from '../../../../../../common/components/links'; +import { APP_UI_ID } from '../../../../../../../common/constants'; +import { SecurityPageName } from '../../../../../../app/types'; +import { getEditRuleUrl } from '../../../../../../common/components/link_to/redirect_to_detection_engine'; +import * as ruleI18n from '../../translations'; + +interface EditRuleSettingButtonLinkProps { + ruleId: string; + disabled: boolean; + disabledReason?: string; +} + +export function EditRuleSettingButtonLink({ + ruleId, + disabled = false, + disabledReason, +}: EditRuleSettingButtonLinkProps): JSX.Element { + const { + application: { navigateToApp }, + } = useKibana().services; + const goToEditRule = useCallback( + (ev) => { + ev.preventDefault(); + navigateToApp(APP_UI_ID, { + deepLinkId: SecurityPageName.rules, + path: getEditRuleUrl(ruleId), + }); + }, + [navigateToApp, ruleId] + ); + + return ( + + + {ruleI18n.EDIT_RULE_SETTINGS} + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index f962cd806cc07..99f8d0554a983 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -27,10 +27,10 @@ import type { ConnectedProps } from 'react-redux'; import { connect, useDispatch } from 'react-redux'; import styled from 'styled-components'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; - import type { Dispatch } from 'redux'; import { isTab } from '@kbn/timelines-plugin/public'; import type { DataViewListItem } from '@kbn/data-views-plugin/common'; +import { isMlRule } from '../../../../../../common/machine_learning/helpers'; import { SecuritySolutionTabNavigation } from '../../../../../common/components/navigation'; import { InputsModelId } from '../../../../../common/store/inputs/constants'; import { @@ -43,7 +43,6 @@ import type { UpdateDateRange } from '../../../../../common/components/charts/co import { FiltersGlobal } from '../../../../../common/components/filters_global'; import { FormattedDate } from '../../../../../common/components/formatted_date'; import { - getEditRuleUrl, getRulesUrl, getDetectionEngineUrl, getRuleDetailsTabUrl, @@ -67,7 +66,7 @@ import { } from '../../../../components/alerts_table/default_config'; import { RuleSwitch } from '../../../../components/rules/rule_switch'; import { StepPanel } from '../../../../components/rules/step_panel'; -import { getStepsData, redirectToDetections, userHasPermissions } from '../helpers'; +import { getStepsData, redirectToDetections } from '../helpers'; import { useGlobalTime } from '../../../../../common/containers/use_global_time'; import { inputsSelectors } from '../../../../../common/store/inputs'; import { setAbsoluteRangeDatePicker } from '../../../../../common/store/inputs/actions'; @@ -76,8 +75,6 @@ import { useMlCapabilities } from '../../../../../common/components/ml/hooks/use import { hasMlAdminPermissions } from '../../../../../../common/machine_learning/has_ml_admin_permissions'; import { hasMlLicense } from '../../../../../../common/machine_learning/has_ml_license'; import { SecurityPageName } from '../../../../../app/types'; -import { LinkButton } from '../../../../../common/components/links'; -import { useFormatUrl } from '../../../../../common/components/link_to'; import { APP_UI_ID, DEFAULT_INDEX_KEY, @@ -97,9 +94,10 @@ import { timelineDefaults } from '../../../../../timelines/store/timeline/defaul import { useSourcererDataView } from '../../../../../common/containers/sourcerer'; import { SourcererScopeName } from '../../../../../common/store/sourcerer/model'; import { - getToolTipContent, + explainLackOfPermission, canEditRuleWithActions, isBoolean, + hasUserCRUDPermission, } from '../../../../../common/utils/privileges'; import { @@ -132,6 +130,7 @@ import { useSignalHelpers } from '../../../../../common/containers/sourcerer/use import { HeaderPage } from '../../../../../common/components/header_page'; import { ExceptionsViewer } from '../../../../../detection_engine/rule_exceptions/components/all_exception_items_table'; import type { NavTab } from '../../../../../common/components/navigation/types'; +import { EditRuleSettingButtonLink } from './components/edit_rule_settings_button_link'; /** * Need a 100% height here to account for the graph/analyze tool, which sets no explicit height parameters, but fills the available space. @@ -301,7 +300,6 @@ const RuleDetailsPageComponent: React.FC = ({ const [showBuildingBlockAlerts, setShowBuildingBlockAlerts] = useState(false); const [showOnlyThreatIndicatorAlerts, setShowOnlyThreatIndicatorAlerts] = useState(false); const mlCapabilities = useMlCapabilities(); - const { formatUrl } = useFormatUrl(SecurityPageName.rules); const { globalFullScreen } = useGlobalFullScreen(); const [filterGroup, setFilterGroup] = useState(FILTER_OPEN); const [dataViewOptions, setDataViewOptions] = useState<{ [x: string]: DataViewListItem }>({}); @@ -586,45 +584,6 @@ const RuleDetailsPageComponent: React.FC = ({ setRule((currentRule) => (currentRule ? { ...currentRule, enabled } : currentRule)); }, []); - const goToEditRule = useCallback( - (ev) => { - ev.preventDefault(); - navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.rules, - path: getEditRuleUrl(ruleId ?? ''), - }); - }, - [navigateToApp, ruleId] - ); - - const editRule = useMemo(() => { - if (!hasActionsPrivileges) { - return ( - - - {ruleI18n.EDIT_RULE_SETTINGS} - - - ); - } - return ( - - {ruleI18n.EDIT_RULE_SETTINGS} - - ); - }, [isExistingRule, canUserCRUD, formatUrl, goToEditRule, hasActionsPrivileges, ruleId]); - const onShowBuildingBlockAlertsChangedCallback = useCallback( (newShowBuildingBlockAlerts: boolean) => { setShowBuildingBlockAlerts(newShowBuildingBlockAlerts); @@ -721,7 +680,12 @@ const RuleDetailsPageComponent: React.FC = ({ = ({ isDisabled={ !isExistingRule || !canEditRuleWithActions(rule, hasActionsPrivileges) || - !userHasPermissions(canUserCRUD) || + !hasUserCRUDPermission(canUserCRUD) || (!hasMlPermissions && !rule?.enabled) } enabled={isExistingRule && (rule?.enabled ?? false)} @@ -742,11 +706,26 @@ const RuleDetailsPageComponent: React.FC = ({ - {editRule} + + + { path: getDetectionEngineUrl(), }); return null; - } else if (!userHasPermissions(canUserCRUD)) { + } else if (!hasUserCRUDPermission(canUserCRUD)) { navigateToApp(APP_UI_ID, { deepLinkId: SecurityPageName.rules, path: getRuleDetailsUrl(ruleId ?? ''), diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx index 4392be5cdc409..f7251806f8f0b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx @@ -18,7 +18,6 @@ import { getPrePackagedRuleStatus, getPrePackagedTimelineStatus, determineDetailsValue, - userHasPermissions, fillEmptySeverityMappings, } from './helpers'; import { mockRuleWithEverything, mockRule } from './all/__mocks__/mock'; @@ -448,29 +447,6 @@ describe('rule helpers', () => { }); }); - describe('userHasPermissions', () => { - test("returns true when user's CRUD operations are null", () => { - const result: boolean = userHasPermissions(null); - const userHasPermissionsExpectedResult = true; - - expect(result).toEqual(userHasPermissionsExpectedResult); - }); - - test('returns false when user cannot CRUD', () => { - const result: boolean = userHasPermissions(false); - const userHasPermissionsExpectedResult = false; - - expect(result).toEqual(userHasPermissionsExpectedResult); - }); - - test('returns true when user can CRUD', () => { - const result: boolean = userHasPermissions(true); - const userHasPermissionsExpectedResult = true; - - expect(result).toEqual(userHasPermissionsExpectedResult); - }); - }); - describe('getPrePackagedRuleStatus', () => { test('ruleNotInstalled', () => { const rulesInstalled = 0; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx index 36e00aaccc1ef..6995abd54e7fb 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx @@ -461,10 +461,6 @@ export const getActionMessageParams = memoizeOne((ruleType: Type | undefined): A export const getAllActionMessageParams = () => transformRuleKeysToActionVariables(getAllRuleParamsKeys()); -// typed as null not undefined as the initial state for this value is null. -export const userHasPermissions = (canUserCRUD: boolean | null): boolean => - canUserCRUD != null ? canUserCRUD : true; - export const MaxWidthEuiFlexItem = styled(EuiFlexItem)` max-width: 1000px; overflow: hidden; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx index 997f40e918cb2..57c0dee2834f7 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx @@ -7,6 +7,7 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import React, { useCallback, useMemo, useState } from 'react'; +import { hasUserCRUDPermission } from '../../../../common/utils/privileges'; import { MlJobUpgradeModal } from '../../../components/modals/ml_job_upgrade_modal'; import { affectedJobIds } from '../../../components/callouts/ml_job_compatibility_callout/affected_job_ids'; import { useInstalledSecurityJobs } from '../../../../common/components/ml/hooks/use_installed_security_jobs'; @@ -26,7 +27,6 @@ import { getPrePackagedRuleStatus, getPrePackagedTimelineStatus, redirectToDetections, - userHasPermissions, } from './helpers'; import * as i18n from './translations'; import { SecurityPageName } from '../../../../app/types'; @@ -126,7 +126,7 @@ const RulesPageComponent: React.FC = () => { const loadPrebuiltRulesAndTemplatesButton = useMemo( () => getLoadPrebuiltRulesAndTemplatesButton({ - isDisabled: !userHasPermissions(canUserCRUD) || loading || loadingJobs, + isDisabled: !hasUserCRUDPermission(canUserCRUD) || loading || loadingJobs, onClick: showMlJobUpgradeModal, }), [ @@ -141,7 +141,7 @@ const RulesPageComponent: React.FC = () => { const reloadPrebuiltRulesAndTemplatesButton = useMemo( () => getReloadPrebuiltRulesAndTemplatesButton({ - isDisabled: !userHasPermissions(canUserCRUD) || loading || loadingJobs, + isDisabled: !hasUserCRUDPermission(canUserCRUD) || loading || loadingJobs, onClick: showMlJobUpgradeModal, }), [ @@ -224,7 +224,7 @@ const RulesPageComponent: React.FC = () => { {i18n.IMPORT_RULE} @@ -235,7 +235,7 @@ const RulesPageComponent: React.FC = () => { data-test-subj="create-new-rule" fill iconType="plusInCircle" - isDisabled={!userHasPermissions(canUserCRUD) || loading} + isDisabled={!hasUserCRUDPermission(canUserCRUD) || loading} deepLinkId={SecurityPageName.rulesCreate} > {i18n.ADD_NEW_RULE} @@ -257,7 +257,7 @@ const RulesPageComponent: React.FC = () => { createPrePackagedRules={createPrePackagedRules} data-test-subj="all-rules" loadingCreatePrePackagedRules={loadingCreatePrePackagedRules} - hasPermissions={userHasPermissions(canUserCRUD)} + hasPermissions={hasUserCRUDPermission(canUserCRUD)} rulesCustomInstalled={rulesCustomInstalled} rulesInstalled={rulesInstalled} rulesNotInstalled={rulesNotInstalled} diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index 8b32821bc71f1..b9948ca90578b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -484,13 +484,20 @@ export const EDIT_RULE_SETTINGS = i18n.translate( } ); -export const EDIT_RULE_SETTINGS_TOOLTIP = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsToolTip', +export const LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaActionsFeaturePrivileges', { defaultMessage: 'You do not have Kibana Actions privileges', } ); +export const LACK_OF_KIBANA_SECURITY_PRIVILEGES = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaSecurityPrivileges', + { + defaultMessage: 'You do not have Kibana Security privileges', + } +); + export const DUPLICATE_RULE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleDescription', { diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index d4698b863029c..5e598674e0c0c 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -27075,7 +27075,7 @@ "xpack.securitySolution.detectionEngine.rules.allRules.actions.deleteRuleDescription": "Supprimer la règle", "xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleDescription": "Dupliquer la règle", "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsDescription": "Modifier les paramètres de règles", - "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsToolTip": "Vous ne disposez pas des privilèges d'actions Kibana", + "xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaActionsFeaturePrivileges": "Vous ne disposez pas des privilèges d'actions Kibana", "xpack.securitySolution.detectionEngine.rules.allRules.actions.exportRuleDescription": "Exporter la règle", "xpack.securitySolution.detectionEngine.rules.allRules.batchActions.deleteSelectedImmutableTitle": "La sélection contient des règles immuables qui ne peuvent pas être supprimées", "xpack.securitySolution.detectionEngine.rules.allRules.batchActionsTitle": "Actions groupées", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index eee20465f90bc..d13339673a297 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -27050,7 +27050,7 @@ "xpack.securitySolution.detectionEngine.rules.allRules.actions.deleteRuleDescription": "ルールの削除", "xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleDescription": "ルールの複製", "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsDescription": "ルール設定の編集", - "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsToolTip": "Kibana アクション特権がありません", + "xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaActionsFeaturePrivileges": "Kibana アクション特権がありません", "xpack.securitySolution.detectionEngine.rules.allRules.actions.exportRuleDescription": "ルールのエクスポート", "xpack.securitySolution.detectionEngine.rules.allRules.batchActions.deleteSelectedImmutableTitle": "選択には削除できないイミュータブルルールがあります", "xpack.securitySolution.detectionEngine.rules.allRules.batchActionsTitle": "一斉アクション", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 3a603dd65fc69..ffd50fd9cbeea 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -27081,7 +27081,7 @@ "xpack.securitySolution.detectionEngine.rules.allRules.actions.deleteRuleDescription": "删除规则", "xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleDescription": "复制规则", "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsDescription": "编辑规则设置", - "xpack.securitySolution.detectionEngine.rules.allRules.actions.editRuleSettingsToolTip": "您没有 Kibana 操作权限", + "xpack.securitySolution.detectionEngine.rules.allRules.actions.lackOfKibanaActionsFeaturePrivileges": "您没有 Kibana 操作权限", "xpack.securitySolution.detectionEngine.rules.allRules.actions.exportRuleDescription": "导出规则", "xpack.securitySolution.detectionEngine.rules.allRules.batchActions.deleteSelectedImmutableTitle": "选择内容包含无法删除的不可变规则", "xpack.securitySolution.detectionEngine.rules.allRules.batchActionsTitle": "批处理操作", From 91edd82b922bcd9f56b5cc277a7393eeb0471ad9 Mon Sep 17 00:00:00 2001 From: Hannah Mudge Date: Mon, 7 Nov 2022 14:13:22 -0700 Subject: [PATCH 6/7] [Dashboard] [Control] Remove support for scripted fields for options list (#144643) (#144744) * Remove support for scripted fields for all controls * Remove support only for options list * Add functional test (cherry picked from commit 508f0127e340e0e29055389af362add64eae7529) --- .../embeddable/options_list_embeddable_factory.tsx | 5 +++-- .../apps/dashboard_elements/controls/options_list.ts | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/plugins/controls/public/options_list/embeddable/options_list_embeddable_factory.tsx b/src/plugins/controls/public/options_list/embeddable/options_list_embeddable_factory.tsx index d0b779e566c31..b7c8f7a5b5b86 100644 --- a/src/plugins/controls/public/options_list/embeddable/options_list_embeddable_factory.tsx +++ b/src/plugins/controls/public/options_list/embeddable/options_list_embeddable_factory.tsx @@ -56,8 +56,9 @@ export class OptionsListEmbeddableFactory public isFieldCompatible = (dataControlField: DataControlField) => { if ( - (dataControlField.field.aggregatable && dataControlField.field.type === 'string') || - dataControlField.field.type === 'boolean' + !dataControlField.field.spec.scripted && + ((dataControlField.field.aggregatable && dataControlField.field.type === 'string') || + dataControlField.field.type === 'boolean') ) { dataControlField.compatibleControlTypes.push(this.type); } diff --git a/test/functional/apps/dashboard_elements/controls/options_list.ts b/test/functional/apps/dashboard_elements/controls/options_list.ts index 56c1778d31def..4f06493574882 100644 --- a/test/functional/apps/dashboard_elements/controls/options_list.ts +++ b/test/functional/apps/dashboard_elements/controls/options_list.ts @@ -172,6 +172,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.clearUnsavedChanges(); }); + it('cannot create options list for scripted field', async () => { + expect(await dashboardControls.optionsListEditorGetCurrentDataView(true)).to.eql( + 'animals-*' + ); + await dashboardControls.openCreateControlFlyout(); + await testSubjects.missingOrFail('field-picker-select-isDog'); + await dashboardControls.controlEditorCancel(true); + }); + after(async () => { await dashboardControls.clearAllControls(); }); From ba69977db79a0c988d4a65dba7990693efa8c975 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 8 Nov 2022 00:24:24 +0200 Subject: [PATCH 7/7] [Security Solution] Fix rule details enable/disable toggle isDisabled state (#143252) (#144738) **Resolves:** [#137149](https://github.com/elastic/kibana/issues/137149) ## Summary Disables rule details enable/disable toggle for ML rules only under basic license. Before: https://user-images.githubusercontent.com/3775283/195514871-f0ccb25e-177d-4b4e-83bc-9c26da1718f0.mov After: https://user-images.githubusercontent.com/3775283/195513340-95944c6d-da6d-4ab3-9917-4e03f5791d3a.mov ### Checklist - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) (cherry picked from commit 931987de6b3b8e51d6032d5c52b4b89ed6c5edd9) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../detections/pages/detection_engine/rules/all/use_columns.tsx | 2 +- .../detections/pages/detection_engine/rules/details/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx index 2fa479d01b5d2..52371046b9aa1 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/use_columns.tsx @@ -84,7 +84,7 @@ const useEnabledColumn = ({ hasCRUDPermissions }: ColumnsProps): TableColumn => isDisabled={ !canEditRuleWithActions(rule, hasActionsPrivileges) || !hasCRUDPermissions || - (isMlRule(rule.type) && !hasMlPermissions && !rule.enabled) + (isMlRule(rule.type) && !hasMlPermissions) } isLoading={loadingIds.includes(rule.id)} /> diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index 99f8d0554a983..0bdbc385df7fc 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -694,7 +694,7 @@ const RuleDetailsPageComponent: React.FC = ({ !isExistingRule || !canEditRuleWithActions(rule, hasActionsPrivileges) || !hasUserCRUDPermission(canUserCRUD) || - (!hasMlPermissions && !rule?.enabled) + (isMlRule(rule?.type) && !hasMlPermissions) } enabled={isExistingRule && (rule?.enabled ?? false)} onChange={handleOnChangeEnabledRule}