diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index 309bf005084c9..3b1e56ddc9010 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -310,6 +310,7 @@ enabled: - x-pack/test/functional/apps/reporting_management/config.ts - x-pack/test/functional/apps/rollup_job/config.ts - x-pack/test/functional/apps/saved_objects_management/config.ts + - x-pack/test/functional/apps/saved_query_management/config.ts - x-pack/test/functional/apps/security/config.ts - x-pack/test/functional/apps/snapshot_restore/config.ts - x-pack/test/functional/apps/spaces/config.ts @@ -401,16 +402,22 @@ enabled: - x-pack/test/upgrade_assistant_integration/config.js - x-pack/test/usage_collection/config.ts - x-pack/test_serverless/api_integration/test_suites/observability/config.ts + - x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts + - x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts - x-pack/test_serverless/api_integration/test_suites/search/config.ts + - x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts - x-pack/test_serverless/api_integration/test_suites/security/config.ts + - x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts - x-pack/test_serverless/functional/test_suites/observability/config.ts - x-pack/test_serverless/functional/test_suites/observability/config.examples.ts - - x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts + - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts - x-pack/test_serverless/functional/test_suites/search/config.ts - x-pack/test_serverless/functional/test_suites/search/config.examples.ts - x-pack/test_serverless/functional/test_suites/search/config.screenshots.ts + - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts - x-pack/test_serverless/functional/test_suites/security/config.ts - x-pack/test_serverless/functional/test_suites/security/config.examples.ts + - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts - x-pack/performance/journeys/ecommerce_dashboard.ts - x-pack/performance/journeys/ecommerce_dashboard_map_only.ts - x-pack/performance/journeys/flight_dashboard.ts diff --git a/.buildkite/pipelines/pull_request/osquery_cypress.yml b/.buildkite/pipelines/pull_request/osquery_cypress.yml index c56d94524f60d..07e26e8f1ff6b 100644 --- a/.buildkite/pipelines/pull_request/osquery_cypress.yml +++ b/.buildkite/pipelines/pull_request/osquery_cypress.yml @@ -25,17 +25,16 @@ steps: artifact_paths: - "target/kibana-osquery/**/*" - # Error: self-signed certificate in certificate chain - # - command: .buildkite/scripts/steps/functional/security_serverless_osquery.sh - # label: 'Serverless Osquery Cypress Tests' - # agents: - # queue: n2-4-spot - # depends_on: build - # timeout_in_minutes: 50 - # parallelism: 6 - # retry: - # automatic: - # - exit_status: '*' - # limit: 1 - # artifact_paths: - # - "target/kibana-osquery/**/*" + - command: .buildkite/scripts/steps/functional/security_serverless_osquery.sh + label: 'Serverless Osquery Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 50 + parallelism: 6 + retry: + automatic: + - exit_status: '*' + limit: 1 + artifact_paths: + - "target/kibana-osquery/**/*" diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8f9261eb8aede..c9f1926a01d21 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -853,6 +853,7 @@ packages/kbn-yarn-lock-validator @elastic/kibana-operations /x-pack/test/examples/search_examples @elastic/kibana-data-discovery /x-pack/test/functional/apps/data_views @elastic/kibana-data-discovery /x-pack/test/functional/apps/discover @elastic/kibana-data-discovery +/x-pack/test/functional/apps/saved_query_management @elastic/kibana-data-discovery /x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/discover @elastic/kibana-data-discovery /x-pack/test/search_sessions_integration @elastic/kibana-data-discovery /x-pack/test/stack_functional_integration/apps/ccs/ccs_discover.js @elastic/kibana-data-discovery diff --git a/examples/state_containers_examples/public/with_data_services/app.tsx b/examples/state_containers_examples/public/with_data_services/app.tsx index 2dda3faf0db88..8a1377c35b854 100644 --- a/examples/state_containers_examples/public/with_data_services/app.tsx +++ b/examples/state_containers_examples/public/with_data_services/app.tsx @@ -97,7 +97,7 @@ export const App = ({ showSearchBar={true} indexPatterns={[dataView]} useDefaultBehaviors={true} - showSaveQuery={true} + saveQueryMenuVisibility="allowed_by_app_privilege" // allowed only for this example app, use `globally_managed` by default /> diff --git a/packages/kbn-crypto/src/__fixtures__/no_ca.p12 b/packages/kbn-crypto/src/__fixtures__/no_ca.p12 index c4beef55cf3b6..5618ae5842c16 100644 Binary files a/packages/kbn-crypto/src/__fixtures__/no_ca.p12 and b/packages/kbn-crypto/src/__fixtures__/no_ca.p12 differ diff --git a/packages/kbn-crypto/src/__fixtures__/no_cert.p12 b/packages/kbn-crypto/src/__fixtures__/no_cert.p12 index 40e4da49f2274..0f1546dd0e114 100644 Binary files a/packages/kbn-crypto/src/__fixtures__/no_cert.p12 and b/packages/kbn-crypto/src/__fixtures__/no_cert.p12 differ diff --git a/packages/kbn-crypto/src/__fixtures__/no_key.p12 b/packages/kbn-crypto/src/__fixtures__/no_key.p12 index 7192bbc7de559..77a5539f9c3e4 100644 Binary files a/packages/kbn-crypto/src/__fixtures__/no_key.p12 and b/packages/kbn-crypto/src/__fixtures__/no_key.p12 differ diff --git a/packages/kbn-crypto/src/__fixtures__/two_cas.p12 b/packages/kbn-crypto/src/__fixtures__/two_cas.p12 index 2de839be3e41c..22e86f87cb429 100644 Binary files a/packages/kbn-crypto/src/__fixtures__/two_cas.p12 and b/packages/kbn-crypto/src/__fixtures__/two_cas.p12 differ diff --git a/packages/kbn-crypto/src/__fixtures__/two_keys.p12 b/packages/kbn-crypto/src/__fixtures__/two_keys.p12 index 784b3033ebf64..5c44d4df3c0d4 100644 Binary files a/packages/kbn-crypto/src/__fixtures__/two_keys.p12 and b/packages/kbn-crypto/src/__fixtures__/two_keys.p12 differ diff --git a/packages/kbn-dev-utils/certs/README.md b/packages/kbn-dev-utils/certs/README.md index 869f18ad2ed23..9df4c5ae60039 100644 --- a/packages/kbn-dev-utils/certs/README.md +++ b/packages/kbn-dev-utils/certs/README.md @@ -37,13 +37,16 @@ __IMPORTANT:__ CA keystore (ca.p12) is not checked in intentionally, talk to @el bin/elasticsearch-certutil ca --out ca.p12 -days 18250 --pass castorepass # Generate the PKCS #12 keystore for Elasticsearch and sign it with the CA -bin/elasticsearch-certutil cert --out elasticsearch.p12 -days 18250 --ca ca.p12 --ca-pass castorepass --name elasticsearch --dns localhost --pass storepass +bin/elasticsearch-certutil cert --out elasticsearch.p12 -days 18250 --ca ca.p12 --ca-pass castorepass --name elasticsearch --dns localhost,host.docker.internal,es01,es02,es03 --pass storepass # Generate the PKCS #12 keystore for Kibana and sign it with the CA -bin/elasticsearch-certutil cert --out kibana.p12 -days 18250 --ca ca.p12 --ca-pass castorepass --name kibana --dns localhost --pass storepass +bin/elasticsearch-certutil cert --out kibana.p12 -days 18250 --ca ca.p12 --ca-pass castorepass --name kibana --dns localhost,host.docker.internal,es01,es02,es03 --pass storepass + +# Generate the PKCS #12 keystore for Fleet Server and sign it with the CA +bin/elasticsearch-certutil cert --out fleet_server.p12 -days 18250 --ca ca.p12 --ca-pass castorepass --name fleet_server --dns localhost,host.docker.internal,es01,es02,es03 --pass storepass # Copy the PKCS #12 keystore for Elasticsearch with an empty password -openssl pkcs12 -in elasticsearch.p12 -nodes -passin pass:"storepass" -passout pass:"" | openssl pkcs12 -export -out elasticsearch_emptypassword.p12 -passout pass:"" +openssl pkcs12 -in elasticsearch.p12 -nodes -passin pass:"storepass" -passout pass:"" | openssl pkcs12 -export -legacy -out elasticsearch_emptypassword.p12 -passout pass:"" # Manually create "elasticsearch_nopassword.p12" -- this can be done on macOS by importing the P12 key store into the Keychain and exporting it again @@ -51,14 +54,20 @@ openssl pkcs12 -in elasticsearch.p12 -nodes -passin pass:"storepass" -passout pa openssl pkcs12 -in elasticsearch.p12 -out ca.crt -cacerts -passin pass:"storepass" -passout pass: # Extract the PEM-formatted PKCS #1 private key for Elasticsearch -openssl pkcs12 -in elasticsearch.p12 -nocerts -passin pass:"storepass" -passout pass:"keypass" | openssl rsa -passin pass:keypass -out elasticsearch.key +openssl pkcs12 -in elasticsearch.p12 -nocerts -passin pass:"storepass" -passout pass:"keypass" | openssl rsa -passin pass:keypass -out elasticsearch.key -traditional # Extract the PEM-formatted X.509 certificate for Elasticsearch openssl pkcs12 -in elasticsearch.p12 -out elasticsearch.crt -clcerts -passin pass:"storepass" -passout pass: # Extract the PEM-formatted PKCS #1 private key for Kibana -openssl pkcs12 -in kibana.p12 -nocerts -passin pass:"storepass" -passout pass:"keypass" | openssl rsa -passin pass:keypass -out kibana.key +openssl pkcs12 -in kibana.p12 -nocerts -passin pass:"storepass" -passout pass:"keypass" | openssl rsa -passin pass:keypass -out kibana.key -traditional # Extract the PEM-formatted X.509 certificate for Kibana openssl pkcs12 -in kibana.p12 -out kibana.crt -clcerts -passin pass:"storepass" -passout pass: + +# Extract the PEM-formatted PKCS #1 private key for Fleet Server +openssl pkcs12 -in fleet_server.p12 -nocerts -passin pass:"storepass" -passout pass:"keypass" | openssl rsa -passin pass:keypass -out fleet_server.key -traditional + +# Extract the PEM-formatted X.509 certificate for Fleet Server +openssl pkcs12 -in fleet_server.p12 -out fleet_server.crt -clcerts -passin pass:"storepass" -passout pass: ``` diff --git a/packages/kbn-dev-utils/certs/ca.crt b/packages/kbn-dev-utils/certs/ca.crt index 3a99c58d6b514..280b5ccf9c0a3 100644 --- a/packages/kbn-dev-utils/certs/ca.crt +++ b/packages/kbn-dev-utils/certs/ca.crt @@ -1,6 +1,6 @@ Bag Attributes friendlyName: elasticsearch - localKeyID: 54 69 6D 65 20 31 36 33 34 31 32 30 31 35 32 31 39 33 + localKeyID: 54 69 6D 65 20 31 36 39 35 34 38 32 34 30 38 35 33 39 Key Attributes: Bag Attributes friendlyName: ca diff --git a/packages/kbn-dev-utils/certs/elasticsearch.crt b/packages/kbn-dev-utils/certs/elasticsearch.crt index a95b7c63ad5ec..09915a0ee3c67 100644 --- a/packages/kbn-dev-utils/certs/elasticsearch.crt +++ b/packages/kbn-dev-utils/certs/elasticsearch.crt @@ -1,29 +1,30 @@ Bag Attributes friendlyName: elasticsearch - localKeyID: 54 69 6D 65 20 31 36 33 34 31 32 30 31 35 32 31 39 33 + localKeyID: 54 69 6D 65 20 31 36 39 35 34 38 32 34 30 38 35 33 39 Key Attributes: Bag Attributes friendlyName: elasticsearch - localKeyID: 54 69 6D 65 20 31 36 33 34 31 32 30 31 35 32 31 39 33 + localKeyID: 54 69 6D 65 20 31 36 39 35 34 38 32 34 30 38 35 33 39 subject=CN = elasticsearch issuer=CN = Elastic Certificate Tool Autogenerated CA -----BEGIN CERTIFICATE----- -MIIDPzCCAiegAwIBAgIUCTO1pAvYtfaJndsQwa9cS/AtoSowDQYJKoZIhvcNAQEL -BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l -cmF0ZWQgQ0EwIBcNMjExMDEzMTAxNTUyWhgPMjA3MTEwMDExMDE1NTJaMBgxFjAU -BgNVBAMTDWVsYXN0aWNzZWFyY2gwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCJK4KLS0kSIM+eqdMq4nO1p7nQ7ADUXIYjeRKaCycSJ7sj//1FRdj2NhLb -gdSX2VGIUZyOw4ptw6bGo0A7KyFE4yJZdG9m+VC1PFck3WaIdQHFdxgMia9deIHx -sU1ETnC4PstdkrsZZpf5+twS6O9TaIQolG6nEShst075v2b3y0NDHcxKW+BtSw27 -HEHlchhP/Uj4haVMABQahfP8gv5vlHqStuOOWeoSgwF5FngCekx+ZeoIf5wVWfE1 -SzDlU7L/JdYOrAp+kN+2g+b4qcr+WvFNCEwbhjJjd9/VIJ5z9kIjJhG9z1NilPhR -RVPG4njS6PxTufejbWN/360HfZbZAgMBAAGjYzBhMB0GA1UdDgQWBBR0kfoZtlNi -ZKxVBPhhpipoXdTQMjAfBgNVHSMEGDAWgBQwTCrAjlvQxik3HBocn1PDUunenjAU -BgNVHREEDTALgglsb2NhbGhvc3QwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOC -AQEAkNcEM6mBzCdECFtuor3lfxrXzmrIo3wUspbv6Rrm4+n6TwJIYp6ydf4OcruR -Uv5feevaYXwDRHBkIEGvhU5po6sGp6k7ppXS5bgrEtAhJSK8SOsLINnbJLnptmZQ -Jharcks5STEqfJFB2QBZvFSLLpvO9g/N8sMro6ZvaUXhfW9DNpd6GIUXQiMhKLex -t80Sb4zuahTRqUSi2j5Hoq8ouc7U9T/RmA3zXNmzq7YvL/gv2it67qdyKvpzoX7t -HJaT1HU0o5Xi/Ol33C/wvfRe05UrHEUil148n/XWz3EJky7El2LYbg36/++mVTHX -xUXS+FdZ1rBlGnGwOHTPHj5FMQ== +MIIDajCCAlKgAwIBAgIVAItVW5PoG88CA9nHe8AQ5KlpBR3NMA0GCSqGSIb3DQEB +CwUAMDQxMjAwBgNVBAMTKUVsYXN0aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2Vu +ZXJhdGVkIENBMCAXDTIzMDkyMzE1MjAwOFoYDzIwNzMwOTEwMTUyMDA4WjAYMRYw +FAYDVQQDEw1lbGFzdGljc2VhcmNoMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA0//9sbn3mgSZTAI2nwHlTWsD9quiXIAnsT2Z1EuZ4qbds/oXKAgD5o1D +pBiRMiqFjvaLSFQx/FpB5ZGYRzgh7gRUHf916ftSugcBtVBDt8BYLMhzwVjpLLC7 +mOYTx8kUd0AvoRsiW23JEmFt8IPtoDj9P9qDhYDoaD5GuAS4EnAea0smtm5G1QMy +FtAsCX1qT1051rYUxlCLan7HeMWmIqPvCR1GzE9vP96Zb2gpAHzg0RHjLDOIDBmZ +DqGS4Egkrc/lvM9LLznqdBj/dzWQI0QQRv6gHzY2oHJorQYQ2xefgFjkdrhy5Sov +LqM+jvd3mUYrkVMgAUNVPYEHXg1clQIDAQABo4GMMIGJMB0GA1UdDgQWBBSomZga +0XXQlnT1T0I/BQ9AmAFdbTAfBgNVHSMEGDAWgBQwTCrAjlvQxik3HBocn1PDUune +njA8BgNVHREENTAzghRob3N0LmRvY2tlci5pbnRlcm5hbIIJbG9jYWxob3N0ggRl +czAzggRlczAyggRlczAxMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBABjM +xPHoqX5PyjPpySKSI2rrwIYlP78NKnwT8kd+Sk2kx0nrIj+GJBluerFTcHMSEQm2 +Z7lAGsAMXxmy3J0PyiFoUlZ5dAaUvjPygbG2YBGRbnxrStXyFQe5R3Bq3dQ62hXl +/eo/UJFAKBzXUcbkrxAR5c/C0kBXAE/z5Qef9CNKGCtFeIeTigYSJd99+ek7hvW0 +2QaI1Cd7qRe3Cy1C8DQMSFN1aB6gaT4FPDoi5pRbr/kX2Ch+JwD+1usKVgqe4sgI +kv2lak2L3rjMtZU9Uh1Kq228TSsagkNN2HadCxeOFPC/ZRs4cxo8cYrhotm8CJt9 +QPfOO517N4ec6b0cIhk= -----END CERTIFICATE----- diff --git a/packages/kbn-dev-utils/certs/elasticsearch.key b/packages/kbn-dev-utils/certs/elasticsearch.key index 4a114a0458a82..cf091f6e96b18 100644 --- a/packages/kbn-dev-utils/certs/elasticsearch.key +++ b/packages/kbn-dev-utils/certs/elasticsearch.key @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAiSuCi0tJEiDPnqnTKuJztae50OwA1FyGI3kSmgsnEie7I//9 -RUXY9jYS24HUl9lRiFGcjsOKbcOmxqNAOyshROMiWXRvZvlQtTxXJN1miHUBxXcY -DImvXXiB8bFNRE5wuD7LXZK7GWaX+frcEujvU2iEKJRupxEobLdO+b9m98tDQx3M -SlvgbUsNuxxB5XIYT/1I+IWlTAAUGoXz/IL+b5R6krbjjlnqEoMBeRZ4AnpMfmXq -CH+cFVnxNUsw5VOy/yXWDqwKfpDftoPm+KnK/lrxTQhMG4YyY3ff1SCec/ZCIyYR -vc9TYpT4UUVTxuJ40uj8U7n3o21jf9+tB32W2QIDAQABAoIBAAdC/+q65hfpF8S5 -Dd5X1bNYuUwXqmWTrmBDYRo5m+xooQ4jV7eqnnVOYIoxYd1WGmxikay3KmVsNbCP -ZO+c9WptsdxVfy5O5ZhqpNxlQi/YLetTxjins1p57jsq3UHP+0StwltmULRkC4im -4K65mS3ruw9g6Ei87kxvGeW73coha0syjORYGcFUynX/DfLi5svUjtSyVUQ1KCiU -KYc0q+SzsgXd71Ngr/HZR4ncCoACW3q/pLp0AUvDY0wZMkACOav2m9D2AnRPbPrA -+/n7LlrD0+LDScZx5nwO3ToFZuTDUXt3G0UWRaQfqiAZxNs2oeOc2gKegEJnPKIo -/BLN/D8CgYEAvMmtcZyrw8vifpP32erSBx2+wftt2JA9GdtZlOxu/kbWH7DAZ75g -YUT0nkcIRrvAS5FCVpOIENZit0RIvA5gM08Brko2mBIRQAbMWmu+c7RUBIa2xVDF -kjputhlWTT7xY03VbJThqUG4oK+zJJSb/RfRM4x2dRYskb7MEwqZFzcCgYEAugFT -t/0Lj+OXR+2pcjPk5VmxjCv4xohNOaX4YZ4/rK4H+gi9iyx232zE/1Dtz5SB4+uw -6hx7Aw3r5U9h1fauT60rSrydChEpFqcfpNQca7HncbF2DDdtEX+ZBkBDZ/U3LJ6Y -pI4o0vCLmiqZYbQ/+4v2f2/5ZqrzyMKLJ3zeqm8CgYAfCHP3ag6eJ+S6c+5ZJw2R -V+Vkk8URxVwV5QXLwjXYnKJUIUTviM7lDmW7oueMYQ6SHXWvL589TVB62cGvEBnm -NUWMdeyVgNrPEI8FChMLiAgLmm1u8AEaMXrDelTCa+dYMJI1wB98KC6GU3t6NueR -ahnchGlwg82dw6ReOO7DbwKBgGe5Sbg2EfaBUeE4dN9MdP44kDu8YZREedwF44Z8 -OsHOooAZ06kCeJ+LBifiN1skU3KIAjXq/+XqI3vSUpqAXx/rT1Lz7xaoDyOkuo6u -AdNEd+38qfmSBu5VGz5TI8ObCNOG9VP+OmG25gJocvP7EhryJ9lU1d0cw6lWY0b3 -6StdAoGBAKUkfbN7qbB+jiZt/6ArYWQE4PL4pqi+B+84xSrp46e41mmocezKhnsp -DxdcuZyg9OXs1xi6AaJtCbelho9bT8jC51GZSFvf887fvGVq7j1TgxWp4mvlqiX7 -tztiggaPXwRZQiThxdJaCIadw26hxdLNOcdGOl/u2m0rudvwybab +MIIEpAIBAAKCAQEA0//9sbn3mgSZTAI2nwHlTWsD9quiXIAnsT2Z1EuZ4qbds/oX +KAgD5o1DpBiRMiqFjvaLSFQx/FpB5ZGYRzgh7gRUHf916ftSugcBtVBDt8BYLMhz +wVjpLLC7mOYTx8kUd0AvoRsiW23JEmFt8IPtoDj9P9qDhYDoaD5GuAS4EnAea0sm +tm5G1QMyFtAsCX1qT1051rYUxlCLan7HeMWmIqPvCR1GzE9vP96Zb2gpAHzg0RHj +LDOIDBmZDqGS4Egkrc/lvM9LLznqdBj/dzWQI0QQRv6gHzY2oHJorQYQ2xefgFjk +drhy5SovLqM+jvd3mUYrkVMgAUNVPYEHXg1clQIDAQABAoIBABXJIPo2VOQ6NEGs +GY5aDMUZqfjblu4ACnQrkycOlNQGl1JjMSV/O11iJ3ERyDv6RCrWmaYXZuKaqNpt +TZOGCHCT98v0YFro5Y2x4iJOiwLzTGxftguItj+OMt0Jyb8WYhjGGw7oga2ZGNhf +dEOK3yy/poC9FRZvUpLB0ZUgAQV92bKRYX8u/GPEwJ9oArOs2vqDZPPvByFT9Ve+ +vFd5DebqLryRog9MpOhx4AUIu3tImL60AarqpmpKUVFwwRoAoN2ZRX989va8zOlR +OMwsFBQbTgoCAcT5lDt2aTB81YiiFVl40s89jomgIrw52mIOkGPCYHTI/5aSnNCp +Q/7qMdkCgYEA7aBeK9OLWGWE7Hxk8sG9BLFcByKpt/twZEEUiYWueyXn/0QHBc2M +deplxYBKee62vLgsw5qlZhR/sPAl33yzE6dBHUHMcsUYPh4FQJItdwhpxgmCDSn0 +1t7r3YMIKQeu1OlSQMteQnsDbdVT9tH0HwnE7MwqaC+AgvP+mq2BUPkCgYEA5GRd +6445rljyZIAx9HF+700LW6YIPFrZ+DWfkbqqelj53v9CazDaefPzkb/bkjyjiig0 +Rz8OuTfq9nfdfneAUSvhUAVPGU/iQ4rv3iAY4VgTPFNSmTYvbyFRwilV0Qn692dc +r/a3Pa7vyTaLZrisF4UDUqnF9Wyfe/YgpIqHK30CgYB/EjEJsrhjbvZkGClLf7r6 +lXWnAyxLDJSPqBW5bNlfVWf4o4I14jNoow4FTZOGHNdvl/WoLDyil/eowOMf3elN +azVw1czk2u0Z2qfoXcMeUktt8YuwSm15sf/jlrx4ZHljtdmceKRRXML6qweZh7DK +IElEb/GFgVFxtdTDFmF+0QKBgQC8sfeu4Cjj1PUe95NORF79UwgpRjnTs7QWkCcv +/atPvidjiD3V1d0LmPQJ3RuJ7LOpN6JJot2FRZ/I1iuXix/m8HwM4vYBEbD84NNh +D9++fkgWNTkvAEecZ0jnQ8N1G+vPcARyFUI7okbWVUxDKBx2qhyetUmqhX4Wqrk5 +eIJI+QKBgQCXYaBPNAOPOpDF9IQKhZOWF4UhGoHV7xR/lVvhPlUNEzMj1lfZIWzj +QcQ1sys1G67ram/Hsz9ZWA15jTCYIdq5SS7tqKO1O+0WTkH9YnyJYvYi3yD/KhT3 +r30+REsprs44RyQvqcV60OCo1xQeM4fNwFL0lJLUedlhrS42/jysyw== -----END RSA PRIVATE KEY----- diff --git a/packages/kbn-dev-utils/certs/elasticsearch.p12 b/packages/kbn-dev-utils/certs/elasticsearch.p12 index 9f88e6bd42a99..a0b01f25d06c8 100644 Binary files a/packages/kbn-dev-utils/certs/elasticsearch.p12 and b/packages/kbn-dev-utils/certs/elasticsearch.p12 differ diff --git a/packages/kbn-dev-utils/certs/elasticsearch_emptypassword.p12 b/packages/kbn-dev-utils/certs/elasticsearch_emptypassword.p12 index 32ba1781d0599..cace9e6a71b01 100644 Binary files a/packages/kbn-dev-utils/certs/elasticsearch_emptypassword.p12 and b/packages/kbn-dev-utils/certs/elasticsearch_emptypassword.p12 differ diff --git a/packages/kbn-dev-utils/certs/elasticsearch_nopassword.p12 b/packages/kbn-dev-utils/certs/elasticsearch_nopassword.p12 index 8ea7d49ab39aa..9b1d6aeb9f1d7 100644 Binary files a/packages/kbn-dev-utils/certs/elasticsearch_nopassword.p12 and b/packages/kbn-dev-utils/certs/elasticsearch_nopassword.p12 differ diff --git a/packages/kbn-dev-utils/certs/fleet_server.crt b/packages/kbn-dev-utils/certs/fleet_server.crt new file mode 100644 index 0000000000000..d88bdad7ec3ea --- /dev/null +++ b/packages/kbn-dev-utils/certs/fleet_server.crt @@ -0,0 +1,30 @@ +Bag Attributes + friendlyName: fleet_server + localKeyID: 54 69 6D 65 20 31 36 39 35 34 38 32 34 31 37 37 31 38 +Key Attributes: +Bag Attributes + friendlyName: fleet_server + localKeyID: 54 69 6D 65 20 31 36 39 35 34 38 32 34 31 37 37 31 38 +subject=CN = fleet_server +issuer=CN = Elastic Certificate Tool Autogenerated CA +-----BEGIN CERTIFICATE----- +MIIDaDCCAlCgAwIBAgIUNsPACNdd6yg9RtG2RjaXhLgcSBcwDQYJKoZIhvcNAQEL +BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l +cmF0ZWQgQ0EwIBcNMjMwOTIzMTUyMDE3WhgPMjA3MzA5MTAxNTIwMTdaMBcxFTAT +BgNVBAMMDGZsZWV0X3NlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALvyofG61gLV5MvhpsVwIecicRbtsbTeirGOrXG6astWUEiR45os/2nb3TkR +3844O4xi2zlaHSVPnK3D5QZCehZWoKhnc7sWrPQbiypEFwQ76IqG4f82jfyl7l6J +SnEpAx6W23zAGGCr5tHNWn0kAUq2ZlLKxuWvR9vp70jzOOl2SZ4q1uj4R+Iu639o +W0kp8oxKrH+N/XOgEzttxSpEfEgs9XCAzUeeGyQf2luv0f2PP6Gw/57VsAoB4Xa+ +Y76MuFD7TjSknS3ipQ9SYJooqwgZA1W9Ba2Myh5r4ypSFfJ59N9Jnu7jyK8DX9S4 +Mjw5/pbReGr8CWQlTck6e7rFFEUCAwEAAaOBjDCBiTAdBgNVHQ4EFgQU1AY1UdL6 +rxUs/nG1sJR57FwJxSAwHwYDVR0jBBgwFoAUMEwqwI5b0MYpNxwaHJ9Tw1Lp3p4w +PAYDVR0RBDUwM4IUaG9zdC5kb2NrZXIuaW50ZXJuYWyCCWxvY2FsaG9zdIIEZXMw +M4IEZXMwMoIEZXMwMTAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAoOpD/ +jk/4uHMvm+e4ICdRpxCMoTmzL1sCXjEyTEIUrtnGajFBQ1Afsh3hRBjmFjpzvagB +78iSmVYPLKvk5vGWhz+f3f5HOfWbKhbfE2tDkXCYb3g9i65hj54RZyBN1jnxW6bs +cMD6h6frwX/KmBKtcuVkgIdUSpAX7MyDvlflvdKJvdOWiTaO30RbmcSJCgchOmcK +9tR7UrzEa4kB0e+MZ62Kmwp+WGzNilwvumrLSUpchaoZ/MJwW4HTvHELeoUERPvs +x6c9UkB2K5rGs28VWjB7QX/+VD6ecUYFXcXX8kvKUU67Mq8HHfhAsSJUUz+kpvan +pNYlrbZ1lKP/lrUL +-----END CERTIFICATE----- diff --git a/packages/kbn-dev-utils/certs/fleet_server.key b/packages/kbn-dev-utils/certs/fleet_server.key new file mode 100644 index 0000000000000..a7c6efd92bd5c --- /dev/null +++ b/packages/kbn-dev-utils/certs/fleet_server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAu/Kh8brWAtXky+GmxXAh5yJxFu2xtN6KsY6tcbpqy1ZQSJHj +miz/advdORHfzjg7jGLbOVodJU+crcPlBkJ6FlagqGdzuxas9BuLKkQXBDvoiobh +/zaN/KXuXolKcSkDHpbbfMAYYKvm0c1afSQBSrZmUsrG5a9H2+nvSPM46XZJnirW +6PhH4i7rf2hbSSnyjEqsf439c6ATO23FKkR8SCz1cIDNR54bJB/aW6/R/Y8/obD/ +ntWwCgHhdr5jvoy4UPtONKSdLeKlD1JgmiirCBkDVb0FrYzKHmvjKlIV8nn030me +7uPIrwNf1LgyPDn+ltF4avwJZCVNyTp7usUURQIDAQABAoIBACCUDj44hKA5M0+j +7aSLq1TFQ5UV3pfbe28LrETqa1iTvZbWsv0mj59p3Q7nakP0u126RQXL+QFeq2nz +at+K5l645WBLjmP/qjsmCxlodBTnzYc1mjcC3dnNaWQ5qA21bjT/MUyOf6tCIOB9 +GBJZC2BH/bScMZ3epDYadr/OaS8OZX0iEKm/pApfjPsNyuIpgnrkEOiUqwCwDr7l +Z0z0wAIPVewN7z1mBoLO3ZT72WR8iKvdXAt982C9z8K4w0YKmVnexD6FHY37uXsE +RHggcRM0psjJ2vpu7Ha1q/pmyAdb8RQ+1tAGApn+DgLRjEdIMX7CvHQFZ2m/+7lC +Y1SUcAECgYEAxXBf0VuR1z9xIdE7i2WteNJtE4zJgO8N0tIMTiRCTGE4kiclCRzX +AN2xiwkvGM2tLo5XC5FvD6AHBdLng1n1xOIgsAgNOAIcjiexm0P/D9EHeOnua7wc +DRQGQgjPNYv9TxPs4K25T9v1uV4hzQFfKq+JyOlzEP5S4vkyHw08AqECgYEA87GW +yidal1nTndAvkBHmYGMu0aHgK0U5NIlgmqqDsqIaES6XATUdjLw2xjiwtwQfEOLm +ZRHc6rgyA0o6QcWhD3TM9X3eJ3Hf4cAETES+rBRTTHY/u71LzjiAQCNAemceWbYX +RAyYYngtMxAyiis/8sFTVNoxGIHHehvLJKIu0yUCgYEArqeHu3Wbf6O5ekbSu69I +U1ch8mdaYVoXCmWRSRa+Jz7hgjhqhLMkZrm2Mt3+8ZwQFN0Jl0whyNqxG6/D6OgN +hwraC54zw1Xq2L24WTc/TEiGqamWpWsUDWWnW4bbdezOOcPQibhj84cKyd3BXM5X +1zTNWBNbHK89t1blxZ45dcECgYEAuRZ44LFjLPEcuRAWD+aIg0zRkobQLA03lZ+B +r/cyb8qO4d3w8wnUl7+cGpGUJm0K61hqhPk8QUoFMlp+RNZFreeYhBxFTtA+qsec +fBD6gNgvLDPj1EPB/68KOayMnGsVsi2LHjQyyRddvRrgR/DxcP9Eu329LE/loeja +Mci8p8ECgYBrIucmzOakwamH5cEI++3UaNHp9AUFsoN8T1Bo7MgdrqGIZ7yUzfzN +ymBeJSN4JJsI3S4tt2fQ2pexfvbk5wAl9sZiR38fRIYMs5NDqRVyISLxd5cbmEqX +04PnNCs3IHpdMA3jfpk0q6wmEtdQNLQWRr3v7e0RvHCG254YY6UN5Q== +-----END RSA PRIVATE KEY----- diff --git a/packages/kbn-dev-utils/certs/fleet_server.p12 b/packages/kbn-dev-utils/certs/fleet_server.p12 new file mode 100644 index 0000000000000..1a270960257ee Binary files /dev/null and b/packages/kbn-dev-utils/certs/fleet_server.p12 differ diff --git a/packages/kbn-dev-utils/certs/kibana.crt b/packages/kbn-dev-utils/certs/kibana.crt index b73885dc7a0f9..ad4afb02212dc 100644 --- a/packages/kbn-dev-utils/certs/kibana.crt +++ b/packages/kbn-dev-utils/certs/kibana.crt @@ -1,29 +1,30 @@ Bag Attributes friendlyName: kibana - localKeyID: 54 69 6D 65 20 31 36 33 34 31 32 30 31 35 38 38 30 33 + localKeyID: 54 69 6D 65 20 31 36 39 35 34 38 32 34 31 34 33 39 35 Key Attributes: Bag Attributes friendlyName: kibana - localKeyID: 54 69 6D 65 20 31 36 33 34 31 32 30 31 35 38 38 30 33 + localKeyID: 54 69 6D 65 20 31 36 39 35 34 38 32 34 31 34 33 39 35 subject=CN = kibana issuer=CN = Elastic Certificate Tool Autogenerated CA -----BEGIN CERTIFICATE----- -MIIDOTCCAiGgAwIBAgIVAN0GVNLw3IaUBuG7t6CeW8w2wyymMA0GCSqGSIb3DQEB -CwUAMDQxMjAwBgNVBAMTKUVsYXN0aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2Vu -ZXJhdGVkIENBMCAXDTIxMTAxMzEwMTU1OFoYDzIwNzExMDAxMTAxNTU4WjARMQ8w -DQYDVQQDEwZraWJhbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3 -nvfL3/26D8EkLso+t9S0m+tSJipLsBWs0dCpc8KRJ/+ijDRnAQ5lOmOAcxt43SNY -KFr0EntQEZyYaRwMIM8aPR0WYW/VV5o4fq2o/JnmHqzZJRJCwZq+5WiCiDPt012N -mRGYCMUxjlEwejue6diLAeQhZ/sfN4jUp217bMEHrhHrNBWTwwJ+Uk5TBQMhviCW -LKbsKrfluA6DGHWrXN4pH7Xmaf/Zyc9AYL/nxwv3VQHZzIAK/U/WNCgFJJ3qoFYY -6TUwDDNa30mSj165OOds9N+VmUlDC3IFiHV3osBWscSU4HJd6QJ8huHrFLLV4y4i -u62el47Qr+/8Ut3SzeIXAgMBAAGjYzBhMB0GA1UdDgQWBBQli5f2bYL9jKUA5Uxp -yRRHeCoPJzAfBgNVHSMEGDAWgBQwTCrAjlvQxik3HBocn1PDUunenjAUBgNVHREE -DTALgglsb2NhbGhvc3QwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEATFNj -WkTBPfgflGYZD4OsYvfT/rVjFKbJP/u1a0rkzNamA2QKNzI9JTOzONPTyRhe9yVS -zeO8X2rtN63l38dtgMjFQ15Xxnp7GFT7GkXfa1JR+tGSGTgVld8nLUzig+mNmBoR -nE4cNc0JJ1PsXPzfPgJ6WMp2WOoNUrQf2cm42i36Jk+7KGcosfyFMPQILZE34Geo -DAgCVpNWPgST4HYBUCHMC7S14LHLVdUXPsfGZPEqU5Zf9Hvy61rQC/RdNjnMI6JD -s57l9oHASNeEg55NQm01aOmwq/z1DXs3UP2nRmp6XCCfE61ghofO5dtV1j3cZ3f5 -dzkzSBV7H6+/MD3Y8Q== +MIIDYjCCAkqgAwIBAgIUZ2p8K7GMXGk6xwCS9S91BUl1JnAwDQYJKoZIhvcNAQEL +BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l +cmF0ZWQgQ0EwIBcNMjMwOTIzMTUyMDE0WhgPMjA3MzA5MTAxNTIwMTRaMBExDzAN +BgNVBAMTBmtpYmFuYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOU +r52dbZ5dY0BoP2p7CEnOpG+qHTNrOAqZO/OJfniPMtpGmwAMl3WZDca6u2XkV2KE +qQyevQ2ADk6G3o8S2RU8mO/+UweuCDF7LHuSdxEGTpucidZErmVhEGUOFosL5UeB +AtIDWxvWwgK+W9Yzt5IEN2HzNCZ6h0dOSk2r9EjVMG5yF4Q6kuqOYxBT7jxoaOtO +OCrgBRummtUga4T13WZ/ZIyyHpXj2+JD4YEmrDyoTa7NLaphv0hnVhHXYoYBI/c6 +2SwwAoBlmtDmlinwSACQ3o/8eLWk0tqkIP14rc3oFh3m7D2c3c2m2HXuyoSDMfGW +beG2IE1Q3idcGmeG3qsCAwEAAaOBjDCBiTAdBgNVHQ4EFgQUMOUM7w5jmIozDvnq +RpM779m5GigwHwYDVR0jBBgwFoAUMEwqwI5b0MYpNxwaHJ9Tw1Lp3p4wPAYDVR0R +BDUwM4IUaG9zdC5kb2NrZXIuaW50ZXJuYWyCCWxvY2FsaG9zdIIEZXMwM4IEZXMw +MoIEZXMwMTAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCxqvQYXSKqgpdl +SP4gXgwipAnYsoW9qkgWQODTvSBEzUdOWme0d3j7i2l6Ur/nVSv5YjkqAv1hf/yJ +Hrk9h+j29ZO/aQ/KDh5i/gTEUnPw3Bxbw47dfn23tjMWO7NCU1fr5HNztRsa/gQr +e9s07g25u/gTfTi9Fyu0lcRe3bXOLS/mFVcuC5oxuS65R9OlbIsiORkZ2EfwuNUf +wAAYOGPIjM2VlQCvBitefsd/SzRKHdxSPy6KSjkO6MGEGo87fr7B7Nx1qp1DVrK7 +q9XeP1Cuygjg9WTcnsvWvNw8CssyuFM6X/3tGjpPasXwLvNUoG2AairK2AYTWhvS +foE31cFg -----END CERTIFICATE----- diff --git a/packages/kbn-dev-utils/certs/kibana.key b/packages/kbn-dev-utils/certs/kibana.key index aae299d430585..a73331ab17874 100644 --- a/packages/kbn-dev-utils/certs/kibana.key +++ b/packages/kbn-dev-utils/certs/kibana.key @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEAt573y9/9ug/BJC7KPrfUtJvrUiYqS7AVrNHQqXPCkSf/oow0 -ZwEOZTpjgHMbeN0jWCha9BJ7UBGcmGkcDCDPGj0dFmFv1VeaOH6tqPyZ5h6s2SUS -QsGavuVogogz7dNdjZkRmAjFMY5RMHo7nunYiwHkIWf7HzeI1Kdte2zBB64R6zQV -k8MCflJOUwUDIb4gliym7Cq35bgOgxh1q1zeKR+15mn/2cnPQGC/58cL91UB2cyA -Cv1P1jQoBSSd6qBWGOk1MAwzWt9Jko9euTjnbPTflZlJQwtyBYh1d6LAVrHElOBy -XekCfIbh6xSy1eMuIrutnpeO0K/v/FLd0s3iFwIDAQABAoIBAAKgqzzHI/Xdfi7l -iS5e6hPQPAytECOMza/vQV7+EZWLLtIlfdB63Y5e8107XclxJ1gpHQLAyvPz3zui -cWzOVrhc5zAn98uOmTM1bjMXXkptO52l3/4wOrsq7upt8YmgjIZXX5Q/N+HZfq7v -aNqsJQBO6B6pmBiJGROrS6/y9/Yt+3jDolgtI6fifYZcMXACoal++BAXbiHYPoff -+nG5lHrAdQoEfNACNnGFlq2O85EWmr3qxUsZV8TblOirAuaUFk5KhhDvTOfTknHY -pW8Z4ttD26+QITyUbI56flgLOfe57y0u4XsOPtWQWEteIBxBFsB9MMj4B8XYdiO/ -hma1jSUCgYEA14H/6vtzM42INgphoj0lHFVL8N0DnuUquR77vQStTO2sDvMQrVTk -BKpy5iYmokHPjY7qV7C37/tQVKdQpUz9Lr0ylwinHwX1KasJkYEJGv++Z59sKH+C -CZX9lZjfTqPpuEonGgPruc8LOXaaM/+g3Nvs7M4S339gnjCZExNzpLsCgYEA2h8z -OhHJpOWOy004HHVjpkWHKTxgZ9xfMLCKjMi1m5sCJ2PCdkd4+wTtkY+u7+iFF1cp -5CVSvZC6fS0rk11ygXix1ZP7cDJj1y4mxvbzWOtPxvZc882Xv0RDXAQBLXgHW6YE -RqvdMczfAx0mbUNke4Umwa5PngSWQAqCYkXNkFUCgYEAhEAY5wEsLyTZxCAWzlMr -pPmLQuK+yBHmZ/hlkBeAqkboYbw0Lcp8q4hWPnqHFufAEST1Fp8yIaleILUUvnxC -mx4sH5eFx3oGe22kz5AaIGF1XW3uF+Q3zt4m4lkQINhiI2AOIt7pF/vA7aCk/OgQ -tbiY6rGDz3gBuNIl/hjfzOUCgYEAy1rDO6RRxnZuhoPbiEy5Ns8jkAJGLw55gL9W -rKKDDiuZ+nc7WWKRHBYgFtFKW0kArB4LZDSXyzwfYYy3T5CTrLmFsoVgqd2Qz5Cr -flvFzGS139zYFETc8OkHk8X4AxggZAWHfwvEESXb1N9ccAmgqLgexftpJv1HxzUF -EfHaEHECgYEArtWvtUdvRQ20r/X/g+mNyUhbYOy15pAgswLK4gIi8rmQPxR08spl -uJJ/cl4fGxG95dl/OV+lNdwl4UcvjATdreEMKvG4X4Cxd+42SUf40M6pGxXoyYz+ -i4WujBaEqBBqjKmYNJVgY7EvqF+VYLBVFZYB1zQhdNPcoPgIH/97vvI= +MIIEpAIBAAKCAQEAw5SvnZ1tnl1jQGg/ansISc6kb6odM2s4Cpk784l+eI8y2kab +AAyXdZkNxrq7ZeRXYoSpDJ69DYAOTobejxLZFTyY7/5TB64IMXsse5J3EQZOm5yJ +1kSuZWEQZQ4WiwvlR4EC0gNbG9bCAr5b1jO3kgQ3YfM0JnqHR05KTav0SNUwbnIX +hDqS6o5jEFPuPGho6044KuAFG6aa1SBrhPXdZn9kjLIelePb4kPhgSasPKhNrs0t +qmG/SGdWEddihgEj9zrZLDACgGWa0OaWKfBIAJDej/x4taTS2qQg/XitzegWHebs +PZzdzabYde7KhIMx8ZZt4bYgTVDeJ1waZ4beqwIDAQABAoIBABaXTBm2n3zVaKt9 +3yVbhL+RwOitC6Zu0hBXVtdwoE0orUUNNsYwriYFQdQcqZzBXV6h2Cz/APNYQU7M +wVRhZvXPBBNkmw6eCZA9nAvCBULQKbBLypgXYtWO+qfRksUI4Lj7q+m6PYHfspVC +i7UYUDHrjsIfp3xyVsHjxy1lmVf4JFAANNHAQeYPR6l5bw/t5yA6qQ9vBtVRz9da +nCE2mQHAODXHMXdiIss4YA3a3uIuN54ud0/cWP/Pn2eM2MHsQYEKFISd7rZ81wlE ++9DmENkL3L9iK0Zx4xUTGGS8R8oM5jimUaa4PQLwoD6IolY0C33Ri6d4IK23AtOH +/+687lECgYEA0oJ2CPNCmbB4Sy7ry3PYZhxZk8qaS5dmYrmB+Z5wNu/mpC2/6M72 +Vkol3BG+5yPgAB4SW09TeRh7VczGu+8juZW1q/Hi1MinhwCfGOvWlIFD9+G4d/gF +5EgWaDwCkimUo218Wry88hCzWuUKyd4HS3PODE0v39Jt1eLSQFGbqEcCgYEA7dha +UBs/I0kPvrYmlDrEH0dJRyvaG5ODv2gqvPtURNqFNMWAZ7146ZTDe2IvZ5bRTikc +B+lwlkMb+yhPvoGX1o3EkOYUhdUcgzSU9nL+ynSoWeOqprJ9Q/al4rIEh8ebvbZI +RF0qvBU6Q8Qg6aA/pcTVHU0+fFe6GDYarWvarH0CgYEAoxYphfOYVGMwPucCDKQa +Mbmi+GnNMeUAkFmxxYam3xjq8aTz+dRlaiKVxDIHWSElCFJD3HPPcpCx9J3qFW1G +mx/OGIEUP8+YYnHr0C3eFz0yQBeih2cigWIL4gMj5sLKAfbvkYiJRWwE19V8jzox +IpZ8OnGONnPbXgoU43mWAz8CgYEA3qvrAYxAtBw2rWmC/Mt3yYDHzeX0MFUOxygS +uxLhdgTPKPSunnD4vlYUHXNyxhygn/hE0fNvAH6bt6up3MUfDjNzj+SX2iQGqZ+U +xpYqjAhjhKRso9v/Ap3r+CyJqUTrPdVmGvrOg3+sKL15wr/QVrXMf75NfcPz6a7d +kvaip1ECgYA/T6EllMlRBM7hMnhZlgt3Ccu/e6VcVzQxqp0EewHzw+N17LdoaWaB +0bw9AqTwLeEhf4s4vidB7pO8YGNkCOKkQ3gqA/pF21VtF4xBRP6iYFa9rEGrHsRU +as68JJ6Lk+gn0aJ0RJNRaOa8xeoA/YWYNfnCfiAHj82UzP5TT4L/BQ== -----END RSA PRIVATE KEY----- diff --git a/packages/kbn-dev-utils/certs/kibana.p12 b/packages/kbn-dev-utils/certs/kibana.p12 index f9e689cf33e04..ea88b940ed8d3 100644 Binary files a/packages/kbn-dev-utils/certs/kibana.p12 and b/packages/kbn-dev-utils/certs/kibana.p12 differ diff --git a/packages/kbn-dev-utils/index.ts b/packages/kbn-dev-utils/index.ts index 2faf0000fde29..0454a0f7395d5 100644 --- a/packages/kbn-dev-utils/index.ts +++ b/packages/kbn-dev-utils/index.ts @@ -8,6 +8,7 @@ export { CA_CERT_PATH, + CA_TRUSTED_FINGERPRINT, ES_KEY_PATH, ES_CERT_PATH, ES_P12_PATH, @@ -18,6 +19,10 @@ export { KBN_CERT_PATH, KBN_P12_PATH, KBN_P12_PASSWORD, + FLEET_SERVER_KEY_PATH, + FLEET_SERVER_CERT_PATH, + FLEET_SERVER_P12_PATH, + FLEET_SERVER_P12_PASSWORD, } from './src/certs'; export * from './src/dev_service_account'; export * from './src/axios'; diff --git a/packages/kbn-dev-utils/src/certs.ts b/packages/kbn-dev-utils/src/certs.ts index 9d1a6077d53c1..b53626cb01fe3 100644 --- a/packages/kbn-dev-utils/src/certs.ts +++ b/packages/kbn-dev-utils/src/certs.ts @@ -9,6 +9,8 @@ import { resolve } from 'path'; export const CA_CERT_PATH = process.env.TEST_CA_CERT_PATH || resolve(__dirname, '../certs/ca.crt'); +export const CA_TRUSTED_FINGERPRINT = + 'F71F73085975FD977339A1909EBFE2DF40DB255E0D5BB56FC37246BF383FFC84'; export const ES_KEY_PATH = resolve(__dirname, '../certs/elasticsearch.key'); export const ES_CERT_PATH = resolve(__dirname, '../certs/elasticsearch.crt'); export const ES_P12_PATH = resolve(__dirname, '../certs/elasticsearch.p12'); @@ -22,3 +24,7 @@ export const KBN_KEY_PATH = resolve(__dirname, '../certs/kibana.key'); export const KBN_CERT_PATH = resolve(__dirname, '../certs/kibana.crt'); export const KBN_P12_PATH = resolve(__dirname, '../certs/kibana.p12'); export const KBN_P12_PASSWORD = 'storepass'; +export const FLEET_SERVER_KEY_PATH = resolve(__dirname, '../certs/fleet_server.key'); +export const FLEET_SERVER_CERT_PATH = resolve(__dirname, '../certs/fleet_server.crt'); +export const FLEET_SERVER_P12_PATH = resolve(__dirname, '../certs/fleet_server.p12'); +export const FLEET_SERVER_P12_PASSWORD = 'storepass'; diff --git a/packages/kbn-dev-utils/src/dev_service_account.ts b/packages/kbn-dev-utils/src/dev_service_account.ts index 32a50f5fcecd2..197ae531df755 100644 --- a/packages/kbn-dev-utils/src/dev_service_account.ts +++ b/packages/kbn-dev-utils/src/dev_service_account.ts @@ -17,3 +17,9 @@ export const kibanaDevServiceAccount = { env.TEST_KIBANA_SERVICE_ACCOUNT_TOKEN || 'AAEAAWVsYXN0aWMva2liYW5hL2tpYmFuYS1kZXY6VVVVVVVVTEstKiBaNA', }; + +export const fleetServerDevServiceAccount = { + token: + env.TEST_FLEET_SERVER_SERVICE_ACCOUNT_TOKEN || + 'AAEAAWVsYXN0aWMvZmxlZXQtc2VydmVyL2ZsZWV0LXNlcnZlci1kZXY6VVo1TWd6MnFTX3FVTWliWGNXNzlwQQ', +}; diff --git a/packages/kbn-es/index.ts b/packages/kbn-es/index.ts index f64664577695f..68256ca572744 100644 --- a/packages/kbn-es/index.ts +++ b/packages/kbn-es/index.ts @@ -12,6 +12,9 @@ export { SYSTEM_INDICES_SUPERUSER, ELASTIC_SERVERLESS_SUPERUSER, ELASTIC_SERVERLESS_SUPERUSER_PASSWORD, + SERVERLESS_NODES, getDockerFileMountPath, + verifyDockerInstalled, + maybeCreateDockerNetwork, } from './src/utils'; export type { ArtifactLicense } from './src/artifact'; diff --git a/packages/kbn-es/src/serverless_resources/README.md b/packages/kbn-es/src/serverless_resources/README.md index 82577579503dc..aa9c0eeafe592 100644 --- a/packages/kbn-es/src/serverless_resources/README.md +++ b/packages/kbn-es/src/serverless_resources/README.md @@ -26,6 +26,7 @@ This section for Service Accounts was originally from the [ES Serverless reposit The "service_tokens" file contains this line: ``` elastic/kibana/kibana-dev:$2a$10$mY2RuGROhk56vLNh.Mgwue98BnkdQPlTR.yGh38ao5jhPJobvuBCq +elastic/fleet-server/fleet-server-dev:$2a$10$tgMX7U09G/EVTP8F/O4zHewhA3DXdv7iM5F2vny9TC6zw77RrutyG ``` That line defines a single service token diff --git a/packages/kbn-es/src/serverless_resources/operator_users.yml b/packages/kbn-es/src/serverless_resources/operator_users.yml index 9040596005236..493b042461688 100644 --- a/packages/kbn-es/src/serverless_resources/operator_users.yml +++ b/packages/kbn-es/src/serverless_resources/operator_users.yml @@ -7,3 +7,8 @@ operator: auth_type: "token" token_source: "file" token_names: [ "kibana-dev" ] + - usernames: [ "elastic/fleet-server" ] + realm_type: "_service_account" + auth_type: "token" + token_source: "file" + token_names: [ "fleet-server-dev" ] diff --git a/packages/kbn-es/src/serverless_resources/service_tokens b/packages/kbn-es/src/serverless_resources/service_tokens index 34bc7476f177f..a4ce74f3db67c 100644 --- a/packages/kbn-es/src/serverless_resources/service_tokens +++ b/packages/kbn-es/src/serverless_resources/service_tokens @@ -1 +1,2 @@ -elastic/kibana/kibana-dev:$2a$10$mY2RuGROhk56vLNh.Mgwue98BnkdQPlTR.yGh38ao5jhPJobvuBCq \ No newline at end of file +elastic/kibana/kibana-dev:$2a$10$mY2RuGROhk56vLNh.Mgwue98BnkdQPlTR.yGh38ao5jhPJobvuBCq +elastic/fleet-server/fleet-server-dev:$2a$10$tgMX7U09G/EVTP8F/O4zHewhA3DXdv7iM5F2vny9TC6zw77RrutyG diff --git a/packages/kbn-es/src/utils/docker.ts b/packages/kbn-es/src/utils/docker.ts index f9ce1e2f391ef..d3d83b7c66cc2 100644 --- a/packages/kbn-es/src/utils/docker.ts +++ b/packages/kbn-es/src/utils/docker.ts @@ -218,7 +218,7 @@ const DOCKER_SSL_ESARGS: Array<[string, string]> = [ ['xpack.security.transport.ssl.keystore.password', ES_P12_PASSWORD], ]; -const SERVERLESS_NODES: Array> = [ +export const SERVERLESS_NODES: Array> = [ { name: 'es01', params: [ diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_top_nav.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_top_nav.tsx index 8963730fcb080..67c51a19052d9 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_top_nav.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_top_nav.tsx @@ -68,7 +68,7 @@ export function DashboardTopNav({ embedSettings, redirectTo }: DashboardTopNavPr navigation: { TopNavMenu }, embeddable: { getStateTransfer }, initializerContext: { allowByValueEmbeddables }, - dashboardCapabilities: { saveQuery: showSaveQuery, showWriteControls }, + dashboardCapabilities: { saveQuery: allowSaveQuery, showWriteControls }, } = pluginServices.getServices(); const isLabsEnabled = uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI); const { setHeaderActionMenu, onAppLeave } = useDashboardMountContext(); @@ -298,7 +298,7 @@ export function DashboardTopNav({ embedSettings, redirectTo }: DashboardTopNavPr useDefaultBehaviors={true} savedQueryId={savedQueryId} indexPatterns={allDataViews} - showSaveQuery={showSaveQuery} + saveQueryMenuVisibility={allowSaveQuery ? 'allowed_by_app_privilege' : 'globally_managed'} appName={LEGACY_DASHBOARD_APP_ID} visible={viewMode !== ViewMode.PRINT} setMenuMountPoint={embedSettings || fullScreenMode ? undefined : setHeaderActionMenu} diff --git a/src/plugins/data/common/search/expressions/esql.ts b/src/plugins/data/common/search/expressions/esql.ts index 8ef0f49588303..ba6600ba0039e 100644 --- a/src/plugins/data/common/search/expressions/esql.ts +++ b/src/plugins/data/common/search/expressions/esql.ts @@ -201,7 +201,7 @@ export const getEsqlFn = ({ getStartDependencies }: EsqlFnArguments) => { } else { const { type, reason } = error.err.attributes; if (type === 'parsing_exception') { - error.message = `Couldn't parse Elasticsearch ES|QL query. You may need to add backticks to names containing special characters. Check your query and try again. Error: ${reason}`; + error.message = `Couldn't parse Elasticsearch ES|QL query. Check your query and try again. Error: ${reason}`; } else { error.message = `Unexpected error from Elasticsearch: ${type} - ${reason}`; } diff --git a/src/plugins/discover/public/application/context/context_app.test.tsx b/src/plugins/discover/public/application/context/context_app.test.tsx index c3f87b0117250..b05dc3ca36e73 100644 --- a/src/plugins/discover/public/application/context/context_app.test.tsx +++ b/src/plugins/discover/public/application/context/context_app.test.tsx @@ -88,7 +88,7 @@ describe('ContextApp test', () => { showSearchBar: true, showQueryInput: false, showFilterBar: true, - showSaveQuery: false, + saveQueryMenuVisibility: 'hidden' as const, showDatePicker: false, indexPatterns: [dataViewMock], useDefaultBehaviors: true, diff --git a/src/plugins/discover/public/application/context/context_app.tsx b/src/plugins/discover/public/application/context/context_app.tsx index de1e0a23c4df2..5c7372f8d1d24 100644 --- a/src/plugins/discover/public/application/context/context_app.tsx +++ b/src/plugins/discover/public/application/context/context_app.tsx @@ -207,7 +207,7 @@ export const ContextApp = ({ dataView, anchorId, referrer }: ContextAppProps) => showSearchBar: true, showQueryInput: false, showFilterBar: true, - showSaveQuery: false, + saveQueryMenuVisibility: 'hidden' as const, showDatePicker: false, indexPatterns: [dataView], useDefaultBehaviors: true, diff --git a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.test.tsx b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.test.tsx index acf966b22ce98..5b00f1ee6e75e 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.test.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.test.tsx @@ -53,8 +53,20 @@ jest.mock('../../../../customizations', () => ({ useDiscoverCustomization: jest.fn(), })); -function getProps(savePermissions = true): DiscoverTopNavProps { - mockDiscoverService.capabilities.discover!.save = savePermissions; +const mockDefaultCapabilities = { + discover: { save: true }, +} as unknown as typeof mockDiscoverService.capabilities; + +function getProps( + { + capabilities, + }: { + capabilities?: Partial; + } = { capabilities: mockDefaultCapabilities } +): DiscoverTopNavProps { + if (capabilities) { + mockDiscoverService.capabilities = capabilities as typeof mockDiscoverService.capabilities; + } const stateContainer = getDiscoverStateMock({ isTimeBased: true }); stateContainer.internalState.transitions.setDataView(dataViewMock); @@ -93,7 +105,7 @@ describe('Discover topnav component', () => { }); test('generated config of TopNavMenu config is correct when discover save permissions are assigned', () => { - const props = getProps(true); + const props = getProps({ capabilities: { discover: { save: true } } }); const component = mountWithIntl( @@ -105,7 +117,7 @@ describe('Discover topnav component', () => { }); test('generated config of TopNavMenu config is correct when no discover save permissions are assigned', () => { - const props = getProps(false); + const props = getProps({ capabilities: { discover: { save: false } } }); const component = mountWithIntl( @@ -116,6 +128,32 @@ describe('Discover topnav component', () => { expect(topMenuConfig).toEqual(['new', 'open', 'share', 'inspect']); }); + test('top nav is correct when discover saveQuery permission is granted', () => { + const props = getProps({ capabilities: { discover: { saveQuery: true } } }); + const component = mountWithIntl( + + + + ); + const statefulSearchBar = component.find( + mockDiscoverService.navigation.ui.AggregateQueryTopNavMenu + ); + expect(statefulSearchBar.props().saveQueryMenuVisibility).toBe('allowed_by_app_privilege'); + }); + + test('top nav is correct when discover saveQuery permission is not granted', () => { + const props = getProps({ capabilities: { discover: { saveQuery: false } } }); + const component = mountWithIntl( + + + + ); + const statefulSearchBar = component.find( + mockDiscoverService.navigation.ui.AggregateQueryTopNavMenu + ); + expect(statefulSearchBar.props().saveQueryMenuVisibility).toBe('globally_managed'); + }); + describe('top nav customization', () => { it('should call getMenuItems', () => { mockUseCustomizations = true; diff --git a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx index a743d4c1abebd..650d5141536e9 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx @@ -220,7 +220,9 @@ export const DiscoverTopNav = ({ savedQueryId={savedQuery} screenTitle={savedSearch.title} showDatePicker={showDatePicker} - showSaveQuery={!isPlainRecord && Boolean(services.capabilities.discover.saveQuery)} + saveQueryMenuVisibility={ + services.capabilities.discover.saveQuery ? 'allowed_by_app_privilege' : 'globally_managed' + } showSearchBar={true} useDefaultBehaviors={true} dataViewPickerOverride={ diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index b74a8b64e8ee3..3b3cac7921813 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -20,7 +20,7 @@ import classNames from 'classnames'; import { MountPoint } from '@kbn/core/public'; import { MountPointPortal } from '@kbn/kibana-react-plugin/public'; import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; -import { StatefulSearchBarProps, SearchBarProps } from '@kbn/unified-search-plugin/public'; +import { StatefulSearchBarProps } from '@kbn/unified-search-plugin/public'; import { AggregateQuery, Query } from '@kbn/es-query'; import { TopNavMenuData } from './top_nav_menu_data'; import { TopNavMenuItem } from './top_nav_menu_item'; @@ -30,38 +30,39 @@ type Badge = EuiBadgeProps & { toolTipProps?: Partial; }; -export type TopNavMenuProps = - StatefulSearchBarProps & - Omit, 'kibana' | 'intl' | 'timeHistory'> & { - config?: TopNavMenuData[]; - badges?: Badge[]; - showSearchBar?: boolean; - showQueryInput?: boolean; - showDatePicker?: boolean; - showFilterBar?: boolean; - unifiedSearch?: UnifiedSearchPublicPluginStart; - className?: string; - visible?: boolean; - /** - * If provided, the menu part of the component will be rendered as a portal inside the given mount point. - * - * This is meant to be used with the `setHeaderActionMenu` core API. - * - * @example - * ```ts - * export renderApp = ({ element, history, setHeaderActionMenu }: AppMountParameters) => { - * const topNavConfig = ...; // TopNavMenuProps - * return ( - * - * - * - * - * ) - * } - * ``` - */ - setMenuMountPoint?: (menuMount: MountPoint | undefined) => void; - }; +export type TopNavMenuProps = Omit< + StatefulSearchBarProps, + 'kibana' | 'intl' | 'timeHistory' +> & { + config?: TopNavMenuData[]; + badges?: Badge[]; + showSearchBar?: boolean; + showQueryInput?: boolean; + showDatePicker?: boolean; + showFilterBar?: boolean; + unifiedSearch?: UnifiedSearchPublicPluginStart; + className?: string; + visible?: boolean; + /** + * If provided, the menu part of the component will be rendered as a portal inside the given mount point. + * + * This is meant to be used with the `setHeaderActionMenu` core API. + * + * @example + * ```ts + * export renderApp = ({ element, history, setHeaderActionMenu }: AppMountParameters) => { + * const topNavConfig = ...; // TopNavMenuProps + * return ( + * + * + * + * + * ) + * } + * ``` + */ + setMenuMountPoint?: (menuMount: MountPoint | undefined) => void; +}; /* * Top Nav Menu is a convenience wrapper component for: diff --git a/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx b/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx index 5cf4795e1ee75..534cd48ade81f 100644 --- a/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx +++ b/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx @@ -174,11 +174,20 @@ const services = { }, }; +const defaultCapabilities = { + savedObjectsManagement: { + edit: true, + }, +}; + setIndexPatterns({ get: () => Promise.resolve(mockIndexPatterns[0]), } as unknown as DataViewsContract); -function wrapSearchBarInContext(testProps: SearchBarProps) { +function wrapSearchBarInContext( + testProps: Partial>, + capabilities: typeof defaultCapabilities = defaultCapabilities +) { const defaultOptions = { appName: 'test', timeHistory: mockTimeHistory, @@ -197,9 +206,16 @@ function wrapSearchBarInContext(testProps: SearchBarProps) { onFiltersUpdated: action('onFiltersUpdated'), } as unknown as SearchBarProps; + const kbnServices = { + ...services, + application: { + capabilities, + }, + }; + return ( - + {...defaultOptions} {...testProps} /> @@ -219,7 +235,7 @@ storiesOf('SearchBar', module) }, onChangeDataView: action('onChangeDataView'), }, - } as SearchBarProps) + }) ) .add('with dataviewPicker enhanced', () => wrapSearchBarInContext({ @@ -234,41 +250,56 @@ storiesOf('SearchBar', module) onAddField: action('onAddField'), onDataViewCreated: action('onDataViewCreated'), }, - } as SearchBarProps) + }) ) .add('with filterBar off', () => wrapSearchBarInContext({ showFilterBar: false, - } as SearchBarProps) + }) ) .add('with query input off', () => wrapSearchBarInContext({ showQueryInput: false, - } as SearchBarProps) + }) ) .add('with date picker off', () => wrapSearchBarInContext({ showDatePicker: false, - } as SearchBarProps) + }) + ) + .add('with disabled "Save query" menu', () => + wrapSearchBarInContext({ + showSaveQuery: false, + }) + ) + .add('with hidden "Manage saved objects" link in "Load saved query" menu', () => + wrapSearchBarInContext( + {}, + { + savedObjectsManagement: { + edit: false, + }, + } + ) ) .add('with the default date picker auto refresh interval on', () => wrapSearchBarInContext({ showDatePicker: true, onRefreshChange: action('onRefreshChange'), - } as SearchBarProps) + }) ) .add('with the default date picker auto refresh interval off', () => wrapSearchBarInContext({ showDatePicker: true, isAutoRefreshDisabled: true, - } as SearchBarProps) + }) ) .add('with only the date picker on', () => wrapSearchBarInContext({ showDatePicker: true, showFilterBar: false, showQueryInput: false, - } as SearchBarProps) + }) ) .add('with additional filters used for suggestions', () => wrapSearchBarInContext({ @@ -470,12 +501,12 @@ storiesOf('SearchBar', module) /> ), showQueryInput: true, - } as SearchBarProps) + }) ) .add('without switch query language', () => wrapSearchBarInContext({ disableQueryLanguageSwitcher: true, - } as SearchBarProps) + }) ) .add('show only query bar without submit', () => wrapSearchBarInContext({ @@ -484,7 +515,7 @@ storiesOf('SearchBar', module) showAutoRefreshOnly: false, showQueryInput: true, showSubmitButton: false, - } as SearchBarProps) + }) ) .add('show only datepicker without submit', () => wrapSearchBarInContext({ @@ -493,7 +524,7 @@ storiesOf('SearchBar', module) showAutoRefreshOnly: false, showQueryInput: false, showSubmitButton: false, - } as SearchBarProps) + }) ) .add('show only query bar and timepicker without submit', () => wrapSearchBarInContext({ @@ -502,7 +533,7 @@ storiesOf('SearchBar', module) showAutoRefreshOnly: false, showQueryInput: true, showSubmitButton: false, - } as SearchBarProps) + }) ) .add('with filter bar on but pinning option is hidden from menus', () => wrapSearchBarInContext({ @@ -621,7 +652,7 @@ storiesOf('SearchBar', module) onChangeDataView: action('onChangeDataView'), }, isDisabled: true, - } as SearchBarProps) + }) ) .add('no submit button', () => wrapSearchBarInContext({ @@ -635,7 +666,7 @@ storiesOf('SearchBar', module) onChangeDataView: action('onChangeDataView'), }, showSubmitButton: false, - } as SearchBarProps) + }) ) .add('submit button always as icon', () => wrapSearchBarInContext({ @@ -649,7 +680,7 @@ storiesOf('SearchBar', module) onChangeDataView: action('onChangeDataView'), }, submitButtonStyle: 'iconOnly', - } as SearchBarProps) + }) ) .add('submit button always as a full button', () => wrapSearchBarInContext({ @@ -663,5 +694,5 @@ storiesOf('SearchBar', module) onChangeDataView: action('onChangeDataView'), }, submitButtonStyle: 'full', - } as SearchBarProps) + }) ); diff --git a/src/plugins/unified_search/public/search_bar/create_search_bar.tsx b/src/plugins/unified_search/public/search_bar/create_search_bar.tsx index 8ffca3fbb0bda..f1f631494dd53 100644 --- a/src/plugins/unified_search/public/search_bar/create_search_bar.tsx +++ b/src/plugins/unified_search/public/search_bar/create_search_bar.tsx @@ -21,6 +21,7 @@ import { useFilterManager } from './lib/use_filter_manager'; import { useTimefilter } from './lib/use_timefilter'; import { useSavedQuery } from './lib/use_saved_query'; import { useQueryStringManager } from './lib/use_query_string_manager'; +import { type SavedQueryMenuVisibility, canShowSavedQuery } from './lib/can_show_saved_query'; import type { UnifiedSearchPublicPluginStart } from '../types'; export interface StatefulSearchBarDeps { @@ -32,14 +33,17 @@ export interface StatefulSearchBarDeps { unifiedSearch: Omit; } -export type StatefulSearchBarProps = - SearchBarOwnProps & { - appName: string; - useDefaultBehaviors?: boolean; - savedQueryId?: string; - onSavedQueryIdChange?: (savedQueryId?: string) => void; - onFiltersUpdated?: (filters: Filter[]) => void; - }; +export type StatefulSearchBarProps = Omit< + SearchBarOwnProps, + 'showSaveQuery' +> & { + appName: string; + useDefaultBehaviors?: boolean; + savedQueryId?: string; + saveQueryMenuVisibility?: SavedQueryMenuVisibility; + onSavedQueryIdChange?: (savedQueryId?: string) => void; + onFiltersUpdated?: (filters: Filter[]) => void; +}; // Respond to user changing the filters const defaultFiltersUpdated = ( @@ -194,6 +198,12 @@ export function createSearchBar({ ); }, [query, timeRange, useDefaultBehaviors]); + const showSaveQuery = canShowSavedQuery({ + saveQueryMenuVisibility: props.saveQueryMenuVisibility, + query, + core, + }); + return ( { + it('should allow when allowed_by_app_privilege', async () => { + expect( + canShowSavedQuery({ + core: coreWithoutGlobalPrivilege, + query: kqlQuery, + saveQueryMenuVisibility: 'allowed_by_app_privilege', + }) + ).toBe(true); + }); + + it('should not allow for text-based queries when allowed_by_app_privilege', async () => { + expect( + canShowSavedQuery({ + core: coreWithoutGlobalPrivilege, + query: esqlQuery, + saveQueryMenuVisibility: 'allowed_by_app_privilege', + }) + ).toBe(false); + }); + + it('should not allow for text-based queries when globally_managed', async () => { + expect( + canShowSavedQuery({ + core: coreWithGlobalPrivilege, + query: esqlQuery, + saveQueryMenuVisibility: 'globally_managed', + }) + ).toBe(false); + }); + + it('should allow when globally allowed', async () => { + expect( + canShowSavedQuery({ + core: coreWithGlobalPrivilege, + query: kqlQuery, + saveQueryMenuVisibility: 'globally_managed', + }) + ).toBe(true); + }); + + it('should not allow when globally disallowed', async () => { + expect( + canShowSavedQuery({ + core: coreWithoutGlobalPrivilege, + query: kqlQuery, + saveQueryMenuVisibility: 'globally_managed', + }) + ).toBe(false); + }); + + it('should not allow when hidden', async () => { + expect( + canShowSavedQuery({ + core: coreWithGlobalPrivilege, + query: kqlQuery, + saveQueryMenuVisibility: 'hidden', + }) + ).toBe(false); + + expect( + canShowSavedQuery({ + core: coreWithGlobalPrivilege, + query: kqlQuery, + saveQueryMenuVisibility: undefined, + }) + ).toBe(false); + }); +}); diff --git a/src/plugins/unified_search/public/search_bar/lib/can_show_saved_query.ts b/src/plugins/unified_search/public/search_bar/lib/can_show_saved_query.ts new file mode 100644 index 0000000000000..bab2fbbe2eb71 --- /dev/null +++ b/src/plugins/unified_search/public/search_bar/lib/can_show_saved_query.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { AggregateQuery, Query } from '@kbn/es-query'; +import type { CoreStart } from '@kbn/core-lifecycle-browser'; +import { isOfAggregateQueryType } from '@kbn/es-query'; + +export type SavedQueryMenuVisibility = + | 'hidden' + | 'globally_managed' // managed by "Saved Query Management" global privilege + | 'allowed_by_app_privilege'; // use only if your Kibana app grants this privilege, otherwise default to `globally_managed` + +export const canShowSavedQuery = ({ + saveQueryMenuVisibility = 'hidden', + query, + core, +}: { + saveQueryMenuVisibility?: SavedQueryMenuVisibility; + query: AggregateQuery | Query | { [key: string]: any }; + core: CoreStart; +}): boolean => { + // don't show Saved Query menu by default + if (!saveQueryMenuVisibility || saveQueryMenuVisibility === 'hidden') { + return false; + } + + // Saved Queries are not supported for text-based languages (only Saved Searches) + if (isOfAggregateQueryType(query)) { + return false; + } + + const isAllowedGlobally = Boolean(core.application.capabilities.savedQueryManagement?.saveQuery); + + // users can allow saving queries globally or grant permission per app + if (saveQueryMenuVisibility === 'allowed_by_app_privilege') { + return true; + } + + return isAllowedGlobally; +}; diff --git a/src/plugins/unified_search/public/search_bar/search_bar.tsx b/src/plugins/unified_search/public/search_bar/search_bar.tsx index b2d3b5abc966c..eb843ee0517ac 100644 --- a/src/plugins/unified_search/public/search_bar/search_bar.tsx +++ b/src/plugins/unified_search/public/search_bar/search_bar.tsx @@ -68,7 +68,7 @@ export interface SearchBarOwnProps { dateRangeTo?: string; // Query bar - should be in SearchBarInjectedDeps query?: QT | Query; - // Show when user has privileges to save + // Show when user has privileges to save. See `canShowSavedQuery(...)` lib. showSaveQuery?: boolean; savedQuery?: SavedQuery; onQueryChange?: (payload: { dateRange: TimeRange; query?: QT | Query }) => void; diff --git a/src/plugins/unified_search/tsconfig.json b/src/plugins/unified_search/tsconfig.json index 8ea28fd9b7f6e..f9c1724e969fd 100644 --- a/src/plugins/unified_search/tsconfig.json +++ b/src/plugins/unified_search/tsconfig.json @@ -40,6 +40,7 @@ "@kbn/text-based-languages", "@kbn/text-based-editor", "@kbn/core-doc-links-browser", + "@kbn/core-lifecycle-browser", ], "exclude": [ "target/**/*", diff --git a/src/plugins/visualizations/public/visualize_app/components/visualize_top_nav.tsx b/src/plugins/visualizations/public/visualize_app/components/visualize_top_nav.tsx index 7e8bf9002af35..5a4e10507701c 100644 --- a/src/plugins/visualizations/public/visualize_app/components/visualize_top_nav.tsx +++ b/src/plugins/visualizations/public/visualize_app/components/visualize_top_nav.tsx @@ -307,7 +307,9 @@ const TopNav = ({ showDatePicker={showDatePicker()} showFilterBar={showFilterBar} showQueryInput={showQueryInput} - showSaveQuery={Boolean(services.visualizeCapabilities.saveQuery)} + saveQueryMenuVisibility={ + services.visualizeCapabilities.saveQuery ? 'allowed_by_app_privilege' : 'globally_managed' + } dataViewPickerComponentProps={ shouldShowDataViewPicker && vis.data.indexPattern ? { @@ -346,7 +348,7 @@ const TopNav = ({ setMenuMountPoint={setHeaderActionMenu} indexPatterns={indexPatterns} showSearchBar - showSaveQuery={false} + saveQueryMenuVisibility="hidden" showDatePicker={false} showQueryInput={false} /> diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index ca639ed3272fd..f54dcb6c13c68 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -250,6 +250,11 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.index_management.enableLegacyTemplates (any)', 'xpack.index_management.enableIndexStats (any)', 'xpack.infra.sources.default.fields.message (array)', + /** + * xpack.infra.featureFlags.metricsExplorerEnabled is conditional based on traditional/serverless offering + * and will resolve to (boolean) + */ + 'xpack.infra.featureFlags.metricsExplorerEnabled (any)', 'xpack.license_management.ui.enabled (boolean)', 'xpack.maps.preserveDrawingBuffer (boolean)', 'xpack.maps.showMapsInspectorAdapter (boolean)', diff --git a/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/base.json b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/base.json new file mode 100644 index 0000000000000..cebc9c2971745 --- /dev/null +++ b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/base.json @@ -0,0 +1,25 @@ +{ + "_meta": { + "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-base.html", + "ecs_version": "8.0.0" + }, + "template": { + "mappings": { + "properties": { + "@timestamp": { + "type": "date" + }, + "labels": { + "type": "object" + }, + "message": { + "type": "match_only_text" + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } +} diff --git a/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/event.json b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/event.json new file mode 100644 index 0000000000000..f235248f3ee83 --- /dev/null +++ b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/event.json @@ -0,0 +1,24 @@ +{ + "_meta": { + "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-event.html", + "ecs_version": "8.0.0" + }, + "template": { + "mappings": { + "properties": { + "event": { + "properties": { + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } +} diff --git a/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/host.json b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/host.json new file mode 100644 index 0000000000000..cc370a5270eba --- /dev/null +++ b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/host.json @@ -0,0 +1,189 @@ +{ + "_meta": { + "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-host.html", + "ecs_version": "8.0.0" + }, + "template": { + "mappings": { + "properties": { + "host": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu": { + "properties": { + "usage": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "disk": { + "properties": { + "read": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "write": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "network": { + "properties": { + "egress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + }, + "ingress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + } + } + } + } + } + } +} diff --git a/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/metricset.json b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/metricset.json new file mode 100644 index 0000000000000..06ef8b57bf4b3 --- /dev/null +++ b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/metricset.json @@ -0,0 +1,18 @@ +{ + "_meta": { + "ecs_version": "8.0.0" + }, + "template": { + "mappings": { + "properties": { + "metricset": { + "properties": { + "interval": { + "type": "long" + } + } + } + } + } + } +} diff --git a/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/system.json b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/system.json new file mode 100644 index 0000000000000..46335a6da442c --- /dev/null +++ b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/component/system.json @@ -0,0 +1,69 @@ +{ + "_meta": { + "ecs_version": "8.0.0" + }, + "template": { + "mappings": { + "properties": { + "system": { + "properties": { + "cpu": { + "properties": { + "cores": { + "type": "integer" + }, + "system": { + "properties": { + "pct": { + "type": "float" + } + } + }, + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + }, + "user": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + }, + "network": { + "properties": { + "in": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "out": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + } + } + } + } + } + } +} diff --git a/x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json new file mode 100644 index 0000000000000..8064e7866e5f6 --- /dev/null +++ b/x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json @@ -0,0 +1,52 @@ +{ + "_meta": { + "description": "Sample composable template that includes all ECS fields", + "ecs_version": "8.0.0" + }, + "composed_of": [ + "ecs_8.0.0_base", + "ecs_8.0.0_event", + "ecs_8.0.0_host", + "ecs_8.0.0_metricset", + "ecs_8.0.0_system" + ], + "index_patterns": [ + "kbn-data-forge-fake_hosts" + ], + "priority": 1, + "template": { + "mappings": { + "_meta": { + "version": "1.6.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "strings_as_keyword": { + "mapping": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ] + }, + "settings": { + "index": { + "codec": "best_compression", + "mapping": { + "total_fields": { + "limit": 2000 + } + } + } + } + } +} diff --git a/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/index.ts b/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/index.ts index f6b685077ec6a..fe969726499b4 100644 --- a/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/index.ts +++ b/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/index.ts @@ -8,7 +8,7 @@ import lodash from 'lodash'; import type { Moment } from 'moment'; -export { template } from './template'; +export { indexTemplate } from './index_template_def'; const createGroupIndex = (index: number) => Math.floor(index / 1000) * 1000; diff --git a/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/index_template_def.ts b/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/index_template_def.ts new file mode 100644 index 0000000000000..ab3876edabf5a --- /dev/null +++ b/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/index_template_def.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as rt from 'io-ts'; +import base from '../composable/component/base.json'; +import event from '../composable/component/event.json'; +import host from '../composable/component/host.json'; +import metricset from '../composable/component/metricset.json'; +import system from '../composable/component/system.json'; + +import template from '../composable/template.json'; +const IndexTemplateDefRT = rt.type({ + namespace: rt.string, + template: rt.UnknownRecord, + components: rt.array(rt.type({ name: rt.string, template: rt.UnknownRecord })), +}); + +export type IndexTemplateDef = rt.TypeOf; + +const ECS_VERSION = template._meta.ecs_version; + +const components = [ + { name: `fake_hosts_${ECS_VERSION}_base`, template: base }, + { name: `fake_hosts_${ECS_VERSION}_event`, template: event }, + { name: `fake_hosts_${ECS_VERSION}_host`, template: host }, + { name: `fake_hosts_${ECS_VERSION}_metricset`, template: metricset }, + { name: `fake_hosts_${ECS_VERSION}_system`, template: system }, +]; + +export const indexTemplate: IndexTemplateDef = { + namespace: 'fake_hosts', + template: { ...template, composed_of: components.map(({ name }) => name) }, + components, +}; diff --git a/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/template.ts b/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/template.ts deleted file mode 100644 index 145002606a789..0000000000000 --- a/x-pack/packages/kbn-infra-forge/src/data_sources/fake_hosts/template.ts +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const template = { - order: 1, - index_patterns: ['kbn-data-forge*'], - settings: { - index: { - mapping: { - total_fields: { - limit: '10000', - }, - }, - number_of_shards: '1', - number_of_replicas: '0', - query: { - default_field: ['message', 'labels.*', 'event.*'], - }, - }, - }, - mappings: { - dynamic_templates: [ - { - labels: { - path_match: 'labels.*', - mapping: { - type: 'keyword', - }, - match_mapping_type: 'string', - }, - }, - { - strings_as_keyword: { - mapping: { - ignore_above: 1024, - type: 'keyword', - }, - match_mapping_type: 'string', - }, - }, - ], - date_detection: false, - properties: { - '@timestamp': { - type: 'date', - }, - tags: { - type: 'keyword', - }, - metricset: { - properties: { - period: { - type: 'long', - }, - }, - }, - host: { - properties: { - name: { - type: 'keyword', - ignore_above: 256, - }, - network: { - properties: { - name: { - type: 'keyword', - ignore_above: 256, - }, - }, - }, - }, - }, - event: { - properties: { - dataset: { - type: 'keyword', - ignore_above: 256, - }, - module: { - type: 'keyword', - ignore_above: 256, - }, - }, - }, - system: { - properties: { - cpu: { - properties: { - cores: { - type: 'long', - }, - total: { - properties: { - norm: { - properties: { - pct: { - scaling_factor: 1000, - type: 'scaled_float', - }, - }, - }, - }, - }, - user: { - properties: { - pct: { - scaling_factor: 1000, - type: 'scaled_float', - }, - norm: { - properties: { - pct: { - scaling_factor: 1000, - type: 'scaled_float', - }, - }, - }, - }, - }, - system: { - properties: { - pct: { - scaling_factor: 1000, - type: 'scaled_float', - }, - }, - }, - }, - }, - network: { - properties: { - name: { - type: 'keyword', - ignore_above: 256, - }, - in: { - properties: { - bytes: { - type: 'long', - }, - }, - }, - out: { - properties: { - bytes: { - type: 'long', - }, - }, - }, - }, - }, - }, - }, - container: { - properties: { - id: { - type: 'keyword', - ignore_above: 256, - }, - name: { - type: 'keyword', - ignore_above: 256, - }, - cpu: { - properties: { - cores: { - type: 'long', - }, - total: { - properties: { - norm: { - properties: { - pct: { - scaling_factor: 1000, - type: 'scaled_float', - }, - }, - }, - }, - }, - user: { - properties: { - pct: { - scaling_factor: 1000, - type: 'scaled_float', - }, - norm: { - properties: { - pct: { - scaling_factor: 1000, - type: 'scaled_float', - }, - }, - }, - }, - }, - system: { - properties: { - pct: { - scaling_factor: 1000, - type: 'scaled_float', - }, - }, - }, - }, - }, - }, - }, - }, - }, - aliases: { - 'metrics-fake_hosts': {}, - }, -}; diff --git a/x-pack/packages/kbn-infra-forge/src/lib/install_template.ts b/x-pack/packages/kbn-infra-forge/src/lib/install_template.ts deleted file mode 100644 index 02e9f1cb8442d..0000000000000 --- a/x-pack/packages/kbn-infra-forge/src/lib/install_template.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { Client } from '@elastic/elasticsearch'; -import type { ToolingLog } from '@kbn/tooling-log'; - -export function installTemplate( - client: Client, - template: object, - namespace: string, - logger: ToolingLog -) { - logger.debug(`installTemplate > template name: kbn-data-forge-${namespace}`); - return client.indices - .putTemplate({ name: `kbn-data-forge-${namespace}`, body: template }) - .catch((error: any) => logger.error(`installTemplate > ${JSON.stringify(error)}`)); -} - -export function deleteTemplate(client: Client, namespace: string, logger: ToolingLog) { - logger.debug(`deleteTemplate > template name: kbn-data-forge-${namespace}`); - return client.indices - .deleteTemplate({ name: `kbn-data-forge-${namespace}` }) - .catch((error: any) => logger.error(`deleteTemplate > ${JSON.stringify(error)}`)); -} diff --git a/x-pack/packages/kbn-infra-forge/src/lib/manage_template.ts b/x-pack/packages/kbn-infra-forge/src/lib/manage_template.ts new file mode 100644 index 0000000000000..722d1cb0b8ac4 --- /dev/null +++ b/x-pack/packages/kbn-infra-forge/src/lib/manage_template.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Client } from '@elastic/elasticsearch'; +import type { ToolingLog } from '@kbn/tooling-log'; +import { IndexTemplateDef } from '../data_sources/fake_hosts/index_template_def'; + +export async function installTemplate( + client: Client, + template: IndexTemplateDef, + namespace: string, + logger: ToolingLog +) { + logger.info(`Installing index templates (${namespace})`); + const componentNames = template.components.map(({ name }) => name); + logger.info(`Installing components for ${template.namespace} (${componentNames})`); + for (const component of template.components) { + await client.cluster + .putComponentTemplate({ + name: component.name, + ...component.template, + }) + .catch((error) => logger.error(`Failed installing component > ${JSON.stringify(error)}`)); + } + logger.info(`Installing index template (${template.namespace})`); + await client.indices + .putIndexTemplate({ + name: template.namespace, + ...template.template, + }) + .catch((error) => logger.error(`Failed installing template > ${JSON.stringify(error)}`)); +} + +export async function deleteTemplate( + client: Client, + template: IndexTemplateDef, + logger: ToolingLog +) { + logger.info(`deleteIndexTemplate > template name: ${template.namespace}`); + await client.indices + .deleteIndexTemplate({ + name: template.namespace, + }) + .catch((error: any) => + logger.error(`deleteIndexTemplate > ${template.namespace} ${JSON.stringify(error)}`) + ); + for (const component of template.components) { + logger.info(`deleteComponents > component name: ${component.name}`); + await client.cluster + .deleteComponentTemplate({ name: component.name }) + .catch((error: any) => + logger.error(`deleteComponents > ${component.name} ${JSON.stringify(error)}`) + ); + } +} diff --git a/x-pack/packages/kbn-infra-forge/src/lib/queue.ts b/x-pack/packages/kbn-infra-forge/src/lib/queue.ts index bf6553fe01b88..75f3affb743d3 100644 --- a/x-pack/packages/kbn-infra-forge/src/lib/queue.ts +++ b/x-pack/packages/kbn-infra-forge/src/lib/queue.ts @@ -24,7 +24,7 @@ export const createQueue = ( logger.debug(`createQueue > index name: ${indexName}`); return async.cargoQueue( (docs: object[], callback) => { - const body: any[] = []; + const body: object[] = []; docs.forEach((doc) => { body.push({ create: { @@ -34,7 +34,7 @@ export const createQueue = ( body.push(omit(doc, 'namespace')); }); esClient - .bulk({ body }) + .bulk({ body, refresh: true }) .then((resp) => { if (resp.errors) { logger.error( diff --git a/x-pack/packages/kbn-infra-forge/src/run.ts b/x-pack/packages/kbn-infra-forge/src/run.ts index 470c0afbdccc6..aad2adb24bc93 100644 --- a/x-pack/packages/kbn-infra-forge/src/run.ts +++ b/x-pack/packages/kbn-infra-forge/src/run.ts @@ -12,7 +12,7 @@ import type { Moment } from 'moment'; import type { ToolingLog } from '@kbn/tooling-log'; import type { Client } from '@elastic/elasticsearch'; import { createQueue, getIndexName } from './lib/queue'; -import { deleteTemplate, installTemplate } from './lib/install_template'; +import { deleteTemplate, installTemplate } from './lib/manage_template'; import * as fakeHosts from './data_sources/fake_hosts'; const generateEventsFns = { @@ -20,7 +20,7 @@ const generateEventsFns = { }; const templates = { - fake_hosts: fakeHosts.template, + fake_hosts: fakeHosts.indexTemplate, }; const EVENTS_PER_CYCLE = 1; @@ -68,5 +68,6 @@ export const generate = async ({ }; export const cleanup = async ({ esClient, logger }: { esClient: Client; logger: ToolingLog }) => { - await deleteTemplate(esClient, DATASET, logger); + const template = templates[DATASET]; + await deleteTemplate(esClient, template, logger); }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx index 22c2c8ff4d7a3..9b6e7bcb60c53 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx @@ -48,7 +48,7 @@ export const FindingsSearchBar = ({ showFilterBar={true} showQueryInput={true} showDatePicker={false} - showSaveQuery={false} + saveQueryMenuVisibility="hidden" isLoading={loading} indexPatterns={[dataView]} onQuerySubmit={setQuery} diff --git a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap index 3edffdda86868..62e868e77e520 100644 --- a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap +++ b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap @@ -177,6 +177,10 @@ Array [ "id": "savedObjectsManagement", "subFeatures": undefined, }, + Object { + "id": "savedQueryManagement", + "subFeatures": undefined, + }, ] `; @@ -469,6 +473,10 @@ Array [ "id": "savedObjectsManagement", "subFeatures": undefined, }, + Object { + "id": "savedQueryManagement", + "subFeatures": undefined, + }, ] `; @@ -975,6 +983,29 @@ Array [ ] `; +exports[`buildOSSFeatures with a basic license returns the savedQueryManagement feature augmented with appropriate sub feature privileges 1`] = ` +Array [ + Object { + "privilege": Object { + "app": Array [ + "kibana", + ], + "catalogue": Array [], + "savedObject": Object { + "all": Array [ + "query", + ], + "read": Array [], + }, + "ui": Array [ + "saveQuery", + ], + }, + "privilegeId": "all", + }, +] +`; + exports[`buildOSSFeatures with a basic license returns the visualize feature augmented with appropriate sub feature privileges 1`] = ` Array [ Object { @@ -1563,6 +1594,29 @@ Array [ ] `; +exports[`buildOSSFeatures with a enterprise license returns the savedQueryManagement feature augmented with appropriate sub feature privileges 1`] = ` +Array [ + Object { + "privilege": Object { + "app": Array [ + "kibana", + ], + "catalogue": Array [], + "savedObject": Object { + "all": Array [ + "query", + ], + "read": Array [], + }, + "ui": Array [ + "saveQuery", + ], + }, + "privilegeId": "all", + }, +] +`; + exports[`buildOSSFeatures with a enterprise license returns the visualize feature augmented with appropriate sub feature privileges 1`] = ` Array [ Object { diff --git a/x-pack/plugins/features/server/oss_features.ts b/x-pack/plugins/features/server/oss_features.ts index 4097780cdfe10..1fee088a25184 100644 --- a/x-pack/plugins/features/server/oss_features.ts +++ b/x-pack/plugins/features/server/oss_features.ts @@ -518,6 +518,31 @@ export const buildOSSFeatures = ({ }, }, }, + { + id: 'savedQueryManagement', + name: i18n.translate('xpack.features.savedQueryManagementFeatureName', { + defaultMessage: 'Saved Query Management', + }), + order: 1750, + category: DEFAULT_APP_CATEGORIES.management, + app: ['kibana'], + catalogue: [], + privilegesTooltip: i18n.translate('xpack.features.savedQueryManagementTooltip', { + defaultMessage: + 'If set to "All", saved queries can be managed across Kibana in all applications that support them. If set to "None", saved query privileges will be determined independently by each application.', + }), + privileges: { + all: { + app: ['kibana'], + catalogue: [], + savedObject: { + all: ['query'], + read: [], + }, + ui: ['saveQuery'], + }, // No read-only mode supported + }, + }, ] as KibanaFeatureConfig[]; }; diff --git a/x-pack/plugins/features/server/plugin.test.ts b/x-pack/plugins/features/server/plugin.test.ts index e1eac3ebbd481..ca88da0458846 100644 --- a/x-pack/plugins/features/server/plugin.test.ts +++ b/x-pack/plugins/features/server/plugin.test.ts @@ -69,6 +69,7 @@ describe('Features Plugin', () => { "filesManagement", "filesSharedImage", "savedObjectsManagement", + "savedQueryManagement", ] `); }); diff --git a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts index 2a523d1a2eabb..d4dea44834a44 100644 --- a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts +++ b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts @@ -11,7 +11,11 @@ import semverGt from 'semver/functions/gt'; import type { Agent } from '../types'; -export function isAgentUpgradeable(agent: Agent, kibanaVersion: string, versionToUpgrade?: string) { +export function isAgentUpgradeable( + agent: Agent, + latestAgentVersion: string, + versionToUpgrade?: string +) { let agentVersion: string; if (typeof agent?.local_metadata?.elastic?.agent?.version === 'string') { agentVersion = agent.local_metadata.elastic.agent.version; @@ -31,23 +35,23 @@ export function isAgentUpgradeable(agent: Agent, kibanaVersion: string, versionT if (versionToUpgrade !== undefined) { return ( isNotDowngrade(agentVersion, versionToUpgrade) && - isAgentVersionLessThanKibana(agentVersion, kibanaVersion) + isAgentVersionLessThanLatest(agentVersion, latestAgentVersion) ); } - return isAgentVersionLessThanKibana(agentVersion, kibanaVersion); + return isAgentVersionLessThanLatest(agentVersion, latestAgentVersion); } -export const isAgentVersionLessThanKibana = (agentVersion: string, kibanaVersion: string) => { +const isAgentVersionLessThanLatest = (agentVersion: string, latestAgentVersion: string) => { // make sure versions are only the number before comparison const agentVersionNumber = semverCoerce(agentVersion); if (!agentVersionNumber) throw new Error('agent version is not valid'); - const kibanaVersionNumber = semverCoerce(kibanaVersion); - if (!kibanaVersionNumber) throw new Error('kibana version is not valid'); + const latestAgentVersionNumber = semverCoerce(latestAgentVersion); + if (!latestAgentVersionNumber) throw new Error('latest version is not valid'); - return semverLt(agentVersionNumber, kibanaVersionNumber); + return semverLt(agentVersionNumber, latestAgentVersionNumber); }; -export const isNotDowngrade = (agentVersion: string, versionToUpgrade: string) => { +const isNotDowngrade = (agentVersion: string, versionToUpgrade: string) => { const agentVersionNumber = semverCoerce(agentVersion); if (!agentVersionNumber) throw new Error('agent version is not valid'); const versionToUpgradeNumber = semverCoerce(versionToUpgrade); diff --git a/x-pack/plugins/fleet/common/types/index.ts b/x-pack/plugins/fleet/common/types/index.ts index 6ef34d045e20f..fc2ad652aae9b 100644 --- a/x-pack/plugins/fleet/common/types/index.ts +++ b/x-pack/plugins/fleet/common/types/index.ts @@ -23,6 +23,7 @@ export interface FleetConfigType { elasticsearch: { hosts?: string[]; ca_sha256?: string; + ca_trusted_fingerprint?: string; }; fleet_server?: { hosts?: string[]; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx index 51c2250e0fe16..2f05354b09a04 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx @@ -12,14 +12,17 @@ import { createFleetTestRendererMock } from '../../../../../../mock'; import type { Agent, AgentPolicy } from '../../../../types'; import { ExperimentalFeaturesService } from '../../../../services'; import { useAuthz } from '../../../../../../hooks/use_authz'; +import { useAgentVersion } from '../../../../../../hooks/use_agent_version'; import { AgentDetailsActionMenu } from './actions_menu'; jest.mock('../../../../../../services/experimental_features'); jest.mock('../../../../../../hooks/use_authz'); +jest.mock('../../../../../../hooks/use_agent_version'); const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService); const mockedUseAuthz = jest.mocked(useAuthz); +const mockedUseAgentVersion = jest.mocked(useAgentVersion); function renderActions({ agent, agentPolicy }: { agent: Agent; agentPolicy?: AgentPolicy }) { const renderer = createFleetTestRendererMock(); @@ -48,6 +51,7 @@ describe('AgentDetailsActionMenu', () => { all: true, }, } as any); + mockedUseAgentVersion.mockReturnValue('8.10.2'); }); describe('Request Diagnotics action', () => { @@ -162,45 +166,90 @@ describe('AgentDetailsActionMenu', () => { expect(res).toBeEnabled(); }); }); -}); -describe('Restart upgrade action', () => { - function renderAndGetRestartUpgradeButton({ - agent, - agentPolicy, - }: { - agent: Agent; - agentPolicy?: AgentPolicy; - }) { - const { utils } = renderActions({ + describe('Restart upgrade action', () => { + function renderAndGetRestartUpgradeButton({ agent, agentPolicy, - }); + }: { + agent: Agent; + agentPolicy?: AgentPolicy; + }) { + const { utils } = renderActions({ + agent, + agentPolicy, + }); - return utils.queryByTestId('restartUpgradeBtn'); - } + return utils.queryByTestId('restartUpgradeBtn'); + } - it('should render an active button', async () => { - const res = renderAndGetRestartUpgradeButton({ - agent: { - status: 'updating', - upgrade_started_at: '2022-11-21T12:27:24Z', - } as any, - agentPolicy: {} as AgentPolicy, + it('should render an active button', async () => { + const res = renderAndGetRestartUpgradeButton({ + agent: { + status: 'updating', + upgrade_started_at: '2022-11-21T12:27:24Z', + } as any, + agentPolicy: {} as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).toBeEnabled(); }); - expect(res).not.toBe(null); - expect(res).toBeEnabled(); + it('should not render action if agent is not stuck in updating', async () => { + const res = renderAndGetRestartUpgradeButton({ + agent: { + status: 'updating', + upgrade_started_at: new Date().toISOString(), + } as any, + agentPolicy: {} as AgentPolicy, + }); + expect(res).toBe(null); + }); }); - it('should not render action if agent is not stuck in updating', async () => { - const res = renderAndGetRestartUpgradeButton({ - agent: { - status: 'updating', - upgrade_started_at: new Date().toISOString(), - } as any, - agentPolicy: {} as AgentPolicy, + describe('Upgrade action', () => { + function renderAndGetUpgradeButton({ + agent, + agentPolicy, + }: { + agent: Agent; + agentPolicy?: AgentPolicy; + }) { + const { utils } = renderActions({ + agent, + agentPolicy, + }); + + return utils.queryByTestId('upgradeBtn'); + } + + it('should render an active action button if agent version is not the latest', async () => { + const res = renderAndGetUpgradeButton({ + agent: { + active: true, + status: 'online', + local_metadata: { elastic: { agent: { version: '8.8.0', upgradeable: true } } }, + } as any, + agentPolicy: {} as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).toBeEnabled(); + }); + + it('should render a disabled action button if agent version is latest', async () => { + const res = renderAndGetUpgradeButton({ + agent: { + active: true, + status: 'online', + local_metadata: { elastic: { agent: { version: '8.10.2', upgradeable: true } } }, + } as any, + agentPolicy: {} as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).not.toBeEnabled(); }); - expect(res).toBe(null); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx index 251a5407de045..d2426dbac8ca5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/actions_menu.tsx @@ -13,7 +13,7 @@ import { isAgentRequestDiagnosticsSupported } from '../../../../../../../common/ import { isStuckInUpdating } from '../../../../../../../common/services/agent_status'; import type { Agent, AgentPolicy } from '../../../../types'; -import { useAuthz, useKibanaVersion } from '../../../../hooks'; +import { useAgentVersion, useAuthz } from '../../../../hooks'; import { ContextMenuActions } from '../../../../components'; import { AgentUnenrollAgentModal, @@ -34,7 +34,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ onCancelReassign?: () => void; }> = memo(({ agent, assignFlyoutOpenByDefault = false, onCancelReassign, agentPolicy }) => { const hasFleetAllPrivileges = useAuthz().fleet.all; - const kibanaVersion = useKibanaVersion(); + const latestAgentVersion = useAgentVersion(); const refreshAgent = useAgentRefresh(); const [isReassignFlyoutOpen, setIsReassignFlyoutOpen] = useState(assignFlyoutOpenByDefault); const [isUnenrollModalOpen, setIsUnenrollModalOpen] = useState(false); @@ -102,11 +102,12 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ , { setIsUpgradeModalOpen(true); }} key="upgradeAgent" + data-test-subj="upgradeBtn" > = memo(({ agent, agentPolicy }) => { - const kibanaVersion = useKibanaVersion(); + const latestAgentVersion = useAgentVersion(); const { displayAgentMetrics } = ExperimentalFeaturesService.get(); return ( @@ -173,7 +173,7 @@ export const AgentDetailsOverviewSection: React.FunctionComponent<{ {agent.local_metadata.elastic.agent.version} - {isAgentUpgradeable(agent, kibanaVersion) ? ( + {latestAgentVersion && isAgentUpgradeable(agent, latestAgentVersion) ? ( = (props: Props) => { const { displayAgentMetrics } = ExperimentalFeaturesService.get(); const { getHref } = useLink(); - const kibanaVersion = useKibanaVersion(); + const latestAgentVersion = useAgentVersion(); const isAgentSelectable = (agent: Agent) => { if (!agent.active) return false; @@ -284,7 +285,9 @@ export const AgentListTable: React.FC = (props: Props) => { {safeMetadata(version)} - {isAgentSelectable(agent) && isAgentUpgradeable(agent, kibanaVersion) ? ( + {isAgentSelectable(agent) && + latestAgentVersion && + isAgentUpgradeable(agent, latestAgentVersion) ? ( @@ -324,7 +327,10 @@ export const AgentListTable: React.FC = (props: Props) => { totalAgents ? showUpgradeable ? agents.filter( - (agent) => isAgentSelectable(agent) && isAgentUpgradeable(agent, kibanaVersion) + (agent) => + isAgentSelectable(agent) && + latestAgentVersion && + isAgentUpgradeable(agent, latestAgentVersion) ) : agents : [] diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx index 17ebb6a6631f9..a2fed8d3ed613 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx @@ -12,14 +12,17 @@ import { createFleetTestRendererMock } from '../../../../../../mock'; import type { Agent, AgentPolicy } from '../../../../types'; import { ExperimentalFeaturesService } from '../../../../services'; import { useAuthz } from '../../../../../../hooks/use_authz'; +import { useAgentVersion } from '../../../../../../hooks/use_agent_version'; import { TableRowActions } from './table_row_actions'; jest.mock('../../../../../../services/experimental_features'); jest.mock('../../../../../../hooks/use_authz'); +jest.mock('../../../../../../hooks/use_agent_version'); const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService); const mockedUseAuthz = jest.mocked(useAuthz); +const mockedUseAgentVersion = jest.mocked(useAgentVersion); function renderTableRowActions({ agent, @@ -57,6 +60,7 @@ describe('TableRowActions', () => { all: true, }, } as any); + mockedUseAgentVersion.mockReturnValue('8.10.2'); }); describe('Request Diagnotics action', () => { @@ -179,4 +183,53 @@ describe('TableRowActions', () => { expect(res).toBe(null); }); }); + + describe('Upgrade action', () => { + function renderAndGetUpgradeButton({ + agent, + agentPolicy, + }: { + agent: Agent; + agentPolicy?: AgentPolicy; + }) { + const { utils } = renderTableRowActions({ + agent, + agentPolicy, + }); + + return utils.queryByTestId('upgradeBtn'); + } + + it('should render an active action button if agent version is not the latest', async () => { + const res = renderAndGetUpgradeButton({ + agent: { + active: true, + status: 'online', + local_metadata: { elastic: { agent: { version: '8.8.0', upgradeable: true } } }, + } as any, + agentPolicy: { + is_managed: false, + } as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).toBeEnabled(); + }); + + it('should render a disabled action button if agent version is latest', async () => { + const res = renderAndGetUpgradeButton({ + agent: { + active: true, + status: 'online', + local_metadata: { elastic: { agent: { version: '8.10.2', upgradeable: true } } }, + } as any, + agentPolicy: { + is_managed: false, + } as AgentPolicy, + }); + + expect(res).not.toBe(null); + expect(res).not.toBeEnabled(); + }); + }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx index 6b36f0a29d587..ba2efb1d86f81 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.tsx @@ -14,7 +14,7 @@ import { isAgentRequestDiagnosticsSupported } from '../../../../../../../common/ import { isStuckInUpdating } from '../../../../../../../common/services/agent_status'; import type { Agent, AgentPolicy } from '../../../../types'; -import { useAuthz, useLink, useKibanaVersion } from '../../../../hooks'; +import { useAuthz, useLink, useAgentVersion } from '../../../../hooks'; import { ContextMenuActions } from '../../../../components'; import { isAgentUpgradeable } from '../../../../services'; import { ExperimentalFeaturesService } from '../../../../services'; @@ -42,7 +42,7 @@ export const TableRowActions: React.FunctionComponent<{ const hasFleetAllPrivileges = useAuthz().fleet.all; const isUnenrolling = agent.status === 'unenrolling'; - const kibanaVersion = useKibanaVersion(); + const latestAgentVersion = useAgentVersion(); const [isMenuOpen, setIsMenuOpen] = useState(false); const { diagnosticFileUploadEnabled, agentTamperProtectionEnabled } = ExperimentalFeaturesService.get(); @@ -107,10 +107,11 @@ export const TableRowActions: React.FunctionComponent<{ { onUpgradeClick(); }} + data-test-subj="upgradeBtn" > { ...jest.requireActual('../../../../hooks'), sendGetAgentsAvailableVersions: jest.fn().mockResolvedValue({ data: { - items: ['8.7.0'], + items: ['8.10.2', '8.7.0'], }, }), sendGetAgentStatus: jest.fn().mockResolvedValue({ data: { results: { updating: 2 } }, }), sendPostBulkAgentUpgrade: jest.fn(), + useAgentVersion: jest.fn().mockReturnValue('8.10.2'), }; }); @@ -86,6 +87,18 @@ describe('AgentUpgradeAgentModal', () => { }); }); + it('should default the version combo to latest agent version', async () => { + const { utils } = renderAgentUpgradeAgentModal({ + agents: [{ id: 'agent1', local_metadata: { host: 'abc' } }] as any, + agentCount: 1, + }); + + const el = utils.getByTestId('agentUpgradeModal.VersionCombobox'); + await waitFor(() => { + expect(el.textContent).toEqual('8.10.2'); + }); + }); + it('should restart uprade on updating agents if some agents in updating', async () => { const { utils } = renderAgentUpgradeAgentModal({ agents: [ diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx index 94e1710cbacb0..7b35927657959 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx @@ -41,6 +41,7 @@ import { useKibanaVersion, useConfig, sendGetAgentStatus, + useAgentVersion, } from '../../../../hooks'; import { sendGetAgentsAvailableVersions } from '../../../../hooks'; @@ -196,6 +197,20 @@ export const AgentUpgradeAgentModal: React.FunctionComponent { + if (latestAgentVersion) { + setSelectedVersion([ + { + label: latestAgentVersion, + value: latestAgentVersion, + }, + ]); + } + }, [latestAgentVersion]); + const [selectedMaintenanceWindow, setSelectedMaintenanceWindow] = useState([ isSmallBatch ? maintenanceOptions[0] : maintenanceOptions[1], ]); diff --git a/x-pack/plugins/fleet/public/mock/plugin_configuration.ts b/x-pack/plugins/fleet/public/mock/plugin_configuration.ts index 5dad8ad504979..935561426d7c2 100644 --- a/x-pack/plugins/fleet/public/mock/plugin_configuration.ts +++ b/x-pack/plugins/fleet/public/mock/plugin_configuration.ts @@ -18,6 +18,7 @@ export const createConfigurationMock = (): FleetConfigType => { elasticsearch: { hosts: [''], ca_sha256: '', + ca_trusted_fingerprint: '', }, }, }; diff --git a/x-pack/plugins/fleet/server/config.ts b/x-pack/plugins/fleet/server/config.ts index f1210a49f7f0c..3dbcf8a795bb1 100644 --- a/x-pack/plugins/fleet/server/config.ts +++ b/x-pack/plugins/fleet/server/config.ts @@ -120,6 +120,7 @@ export const config: PluginConfigDescriptor = { elasticsearch: schema.object({ hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))), ca_sha256: schema.maybe(schema.string()), + ca_trusted_fingerprint: schema.maybe(schema.string()), }), fleet_server: schema.maybe( schema.object({ diff --git a/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts b/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts index f13044d975396..fedef7b4957ca 100644 --- a/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts +++ b/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts @@ -24,6 +24,7 @@ import { getAgentById } from '../../services/agents'; import type { Agent } from '../../types'; import { getAllFleetServerAgents } from '../../collectors/get_all_fleet_server_agents'; +import { getLatestAvailableVersion } from '../../services/agents/versions'; export const postAgentUpgradeHandler: RequestHandler< TypeOf, @@ -35,6 +36,7 @@ export const postAgentUpgradeHandler: RequestHandler< const esClient = coreContext.elasticsearch.client.asInternalUser; const { version, source_uri: sourceUri, force } = request.body; const kibanaVersion = appContextService.getKibanaVersion(); + const latestAgentVersion = await getLatestAvailableVersion(); try { checkKibanaVersion(version, kibanaVersion, force); } catch (err) { @@ -73,7 +75,7 @@ export const postAgentUpgradeHandler: RequestHandler< }, }); } - if (!force && !isAgentUpgradeable(agent, kibanaVersion, version)) { + if (!force && !isAgentUpgradeable(agent, latestAgentVersion, version)) { return response.customError({ statusCode: 400, body: { diff --git a/x-pack/plugins/fleet/server/services/agents/crud.ts b/x-pack/plugins/fleet/server/services/agents/crud.ts index b6a124d3c32ab..1521a19f51af1 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud.ts @@ -24,6 +24,7 @@ import { auditLoggingService } from '../audit_logging'; import { searchHitToAgent, agentSOAttributesToFleetServerAgentDoc } from './helpers'; import { buildAgentStatusRuntimeField } from './build_status_runtime_field'; +import { getLatestAvailableVersion } from './versions'; const INACTIVE_AGENT_CONDITION = `status:inactive OR status:unenrolled`; const ACTIVE_AGENT_CONDITION = `NOT (${INACTIVE_AGENT_CONDITION})`; @@ -302,6 +303,7 @@ export async function getAgentsByKuery( // filtering for a range on the version string will not work, // nor does filtering on a flattened field (local_metadata), so filter here if (showUpgradeable) { + const latestAgentVersion = await getLatestAvailableVersion(); // fixing a bug where upgradeable filter was not returning right results https://github.com/elastic/kibana/issues/117329 // query all agents, then filter upgradeable, and return the requested page and correct total // if there are more than SO_SEARCH_LIMIT agents, the logic falls back to same as before @@ -309,14 +311,12 @@ export async function getAgentsByKuery( const response = await queryAgents(0, SO_SEARCH_LIMIT); agents = response.hits.hits .map(searchHitToAgent) - .filter((agent) => isAgentUpgradeable(agent, appContextService.getKibanaVersion())); + .filter((agent) => isAgentUpgradeable(agent, latestAgentVersion)); total = agents.length; const start = (page - 1) * perPage; agents = agents.slice(start, start + perPage); } else { - agents = agents.filter((agent) => - isAgentUpgradeable(agent, appContextService.getKibanaVersion()) - ); + agents = agents.filter((agent) => isAgentUpgradeable(agent, latestAgentVersion)); } } diff --git a/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts b/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts index 8b7409375fb2a..014a9bec89739 100644 --- a/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/upgrade_action_runner.ts @@ -26,6 +26,7 @@ import { createErrorActionResults, createAgentAction } from './actions'; import { getHostedPolicies, isHostedAgent } from './hosted_agent'; import { BulkActionTaskType } from './bulk_action_types'; import { getCancelledActions } from './action_status'; +import { getLatestAvailableVersion } from './versions'; export class UpgradeActionRunner extends ActionRunner { protected async processAgents(agents: Agent[]): Promise<{ actionId: string }> { @@ -72,12 +73,12 @@ export async function upgradeBatch( ? givenAgents.filter((agent: Agent) => !isHostedAgent(hostedPolicies, agent)) : givenAgents; - const kibanaVersion = appContextService.getKibanaVersion(); + const latestAgentVersion = await getLatestAvailableVersion(); const upgradeableResults = await Promise.allSettled( agentsToCheckUpgradeable.map(async (agent) => { // Filter out agents currently unenrolling, unenrolled, or not upgradeable b/c of version check const isNotAllowed = - !options.force && !isAgentUpgradeable(agent, kibanaVersion, options.version); + !options.force && !isAgentUpgradeable(agent, latestAgentVersion, options.version); if (isNotAllowed) { throw new FleetError(`Agent ${agent.id} is not upgradeable`); } diff --git a/x-pack/plugins/fleet/server/services/agents/versions.test.ts b/x-pack/plugins/fleet/server/services/agents/versions.test.ts index 6274fe421527a..92e30141c006a 100644 --- a/x-pack/plugins/fleet/server/services/agents/versions.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/versions.test.ts @@ -30,7 +30,7 @@ describe('getAvailableVersions', () => { mockKibanaVersion = '300.0.0'; mockedReadFile.mockResolvedValue(`["8.1.0", "8.0.0", "7.17.0", "7.16.0"]`); - const res = await getAvailableVersions({ cached: false }); + const res = await getAvailableVersions({ cached: false, includeCurrentVersion: true }); expect(res).toEqual(['300.0.0', '8.1.0', '8.0.0', '7.17.0']); }); @@ -39,11 +39,11 @@ describe('getAvailableVersions', () => { mockKibanaVersion = '300.0.0-SNAPSHOT'; mockedReadFile.mockResolvedValue(`["8.1.0", "8.0.0", "7.17.0", "7.16.0"]`); - const res = await getAvailableVersions({ cached: false }); + const res = await getAvailableVersions({ cached: false, includeCurrentVersion: true }); expect(res).toEqual(['300.0.0-SNAPSHOT', '8.1.0', '8.0.0', '7.17.0']); }); - it('should not include the current version if onlyAllowAgentUpgradeToKnownVersions = true', async () => { + it('should not include the current version if includeCurrentVersion is not set', async () => { mockKibanaVersion = '300.0.0-SNAPSHOT'; mockConfig = { internal: { @@ -65,4 +65,18 @@ describe('getAvailableVersions', () => { expect(res).toEqual(['8.1.0', '8.0.0', '7.17.0']); }); + + it('should return kibana version only if cannot read versions', async () => { + mockKibanaVersion = '300.0.0'; + mockConfig = { + internal: { + onlyAllowAgentUpgradeToKnownVersions: false, + }, + }; + mockedReadFile.mockRejectedValue({ code: 'ENOENT' }); + + const res = await getAvailableVersions({ cached: false }); + + expect(res).toEqual(['300.0.0']); + }); }); diff --git a/x-pack/plugins/fleet/server/services/agents/versions.ts b/x-pack/plugins/fleet/server/services/agents/versions.ts index 90436de70d7d0..fda703056daa5 100644 --- a/x-pack/plugins/fleet/server/services/agents/versions.ts +++ b/x-pack/plugins/fleet/server/services/agents/versions.ts @@ -60,8 +60,7 @@ export const getAvailableVersions = async ({ .sort((a: any, b: any) => (semverGt(a, b) ? -1 : 1)); versionsToDisplay = uniq(versions) as string[]; - const appendCurrentVersion = - includeCurrentVersion ?? !config?.internal?.onlyAllowAgentUpgradeToKnownVersions; + const appendCurrentVersion = includeCurrentVersion; if (appendCurrentVersion) { // Add current version if not already present diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts index fda7789356956..1023e1bdb7b56 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts @@ -89,6 +89,7 @@ describe('output preconfiguration', () => { Array [ Object { "ca_sha256": undefined, + "ca_trusted_fingerprint": undefined, "hosts": Array [ "http://elasticsearc:9201", ], diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts index 5f8f1a13feda9..5bc7c452b481e 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts @@ -30,6 +30,7 @@ export function getPreconfiguredOutputFromConfig(config?: FleetConfigType) { id: DEFAULT_OUTPUT_ID, hosts: config?.agents.elasticsearch.hosts, ca_sha256: config?.agents.elasticsearch.ca_sha256, + ca_trusted_fingerprint: config?.agents.elasticsearch.ca_trusted_fingerprint, is_preconfigured: true, } as PreconfiguredOutput, ] diff --git a/x-pack/plugins/infra/common/http_api/metrics_explorer_views/v1/common.ts b/x-pack/plugins/infra/common/http_api/metrics_explorer_views/v1/common.ts index 8e8d1e755c8dd..22aa3350ceee3 100644 --- a/x-pack/plugins/infra/common/http_api/metrics_explorer_views/v1/common.ts +++ b/x-pack/plugins/infra/common/http_api/metrics_explorer_views/v1/common.ts @@ -9,7 +9,8 @@ import { either } from 'fp-ts/Either'; import { metricsExplorerViewRT } from '../../../metrics_explorer_views'; export const METRICS_EXPLORER_VIEW_URL = '/api/infra/metrics_explorer_views'; -export const METRICS_EXPLORER_VIEW_URL_ENTITY = `${METRICS_EXPLORER_VIEW_URL}/{metricsExplorerViewId}`; +export const METRICS_EXPLORER_VIEW_URL_ENTITY = + `${METRICS_EXPLORER_VIEW_URL}/{metricsExplorerViewId}` as const; export const getMetricsExplorerViewUrl = (metricsExplorerViewId?: string) => [METRICS_EXPLORER_VIEW_URL, metricsExplorerViewId].filter(Boolean).join('/'); diff --git a/x-pack/plugins/infra/common/plugin_config_types.ts b/x-pack/plugins/infra/common/plugin_config_types.ts index adff4cabe30a5..89bbd1dbe4e5b 100644 --- a/x-pack/plugins/infra/common/plugin_config_types.ts +++ b/x-pack/plugins/infra/common/plugin_config_types.ts @@ -25,10 +25,14 @@ export interface InfraConfig { }; }; }; + featureFlags: { + metricsExplorerEnabled: boolean; + }; } export const publicConfigKeys = { sources: true, + featureFlags: true, } as const; export type InfraPublicConfigKey = keyof { diff --git a/x-pack/plugins/infra/public/apps/metrics_app.tsx b/x-pack/plugins/infra/public/apps/metrics_app.tsx index 5366019d5ad8e..2da9e16995148 100644 --- a/x-pack/plugins/infra/public/apps/metrics_app.tsx +++ b/x-pack/plugins/infra/public/apps/metrics_app.tsx @@ -13,6 +13,7 @@ import { Router, Routes, Route } from '@kbn/shared-ux-router'; import { AppMountParameters } from '@kbn/core/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import '../index.scss'; +import { InfraPublicConfig } from '../../common/plugin_config_types'; import { LinkToMetricsPage } from '../pages/link_to/link_to_metrics'; import { InfrastructurePage } from '../pages/metrics'; import { InfraClientStartDeps, InfraClientStartExports } from '../types'; @@ -20,6 +21,7 @@ import { RedirectWithQueryParams } from '../utils/redirect_with_query_params'; import { CommonInfraProviders, CoreProviders } from './common_providers'; import { prepareMountElement } from './common_styles'; import { SourceProvider } from '../containers/metrics_source'; +import { PluginConfigProvider } from '../containers/plugin_config_context'; export const METRICS_APP_DATA_TEST_SUBJ = 'infraMetricsPage'; @@ -27,6 +29,7 @@ export const renderApp = ( core: CoreStart, plugins: InfraClientStartDeps, pluginStart: InfraClientStartExports, + pluginConfig: InfraPublicConfig, { element, history, setHeaderActionMenu, theme$ }: AppMountParameters ) => { const storage = new Storage(window.localStorage); @@ -39,6 +42,7 @@ export const renderApp = ( history={history} plugins={plugins} pluginStart={pluginStart} + pluginConfig={pluginConfig} setHeaderActionMenu={setHeaderActionMenu} storage={storage} theme$={theme$} @@ -56,11 +60,21 @@ const MetricsApp: React.FC<{ core: CoreStart; history: History; pluginStart: InfraClientStartExports; + pluginConfig: InfraPublicConfig; plugins: InfraClientStartDeps; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; storage: Storage; theme$: AppMountParameters['theme$']; -}> = ({ core, history, pluginStart, plugins, setHeaderActionMenu, storage, theme$ }) => { +}> = ({ + core, + history, + pluginStart, + pluginConfig, + plugins, + setHeaderActionMenu, + storage, + theme$, +}) => { const uiCapabilities = core.application.capabilities; return ( @@ -74,23 +88,25 @@ const MetricsApp: React.FC<{ observabilityAIAssistant={plugins.observabilityAIAssistant} > - - - - {uiCapabilities?.infrastructure?.show && ( - - )} - {uiCapabilities?.infrastructure?.show && ( - - )} - {uiCapabilities?.infrastructure?.show && ( - - )} - {uiCapabilities?.infrastructure?.show && ( - - )} - - + + + + + {uiCapabilities?.infrastructure?.show && ( + + )} + {uiCapabilities?.infrastructure?.show && ( + + )} + {uiCapabilities?.infrastructure?.show && ( + + )} + {uiCapabilities?.infrastructure?.show && ( + + )} + + + diff --git a/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx b/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx new file mode 100644 index 0000000000000..2b89e4b996da2 --- /dev/null +++ b/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import React from 'react'; +import { PluginConfigProvider, usePluginConfig } from './plugin_config_context'; + +describe('usePluginConfig()', () => { + it('throws an error if the context value was not set before using the hook', () => { + const { result } = renderHook(() => usePluginConfig()); + + expect(result.error).not.toEqual(undefined); + }); + + it('returns the plugin config what was set through the provider', () => { + const config = { + featureFlags: { metricsExplorerEnabled: false }, + }; + const { result } = renderHook(() => usePluginConfig(), { + wrapper: ({ children }) => { + return {children}; + }, + }); + + expect(result.error).toEqual(undefined); + expect(result.current).toEqual(config); + }); +}); diff --git a/x-pack/plugins/infra/public/containers/plugin_config_context.ts b/x-pack/plugins/infra/public/containers/plugin_config_context.ts new file mode 100644 index 0000000000000..a9b91c3f1aaa3 --- /dev/null +++ b/x-pack/plugins/infra/public/containers/plugin_config_context.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createContext, useContext } from 'react'; +import { InfraPublicConfig } from '../../common/plugin_config_types'; + +const PluginConfigContext = createContext(undefined); + +export const usePluginConfig = (): InfraPublicConfig => { + const context = useContext(PluginConfigContext); + + if (context === undefined) { + throw new Error( + 'PluginConfigContext value was not initialized. Use context provider to set the value before using it.' + ); + } + + return context; +}; + +export const PluginConfigProvider = PluginConfigContext.Provider; diff --git a/x-pack/plugins/infra/public/hooks/use_metrics_explorer_views.ts b/x-pack/plugins/infra/public/hooks/use_metrics_explorer_views.ts index dac743a1f2191..7e0eb3bd387a1 100644 --- a/x-pack/plugins/infra/public/hooks/use_metrics_explorer_views.ts +++ b/x-pack/plugins/infra/public/hooks/use_metrics_explorer_views.ts @@ -24,10 +24,10 @@ import { UpdateMetricsExplorerViewAttributesRequestPayload, } from '../../common/http_api/latest'; import { MetricsExplorerView } from '../../common/metrics_explorer_views'; -import { useKibanaContextForPlugin } from './use_kibana'; import { useUrlState } from '../utils/use_url_state'; import { useSavedViewsNotifier } from './use_saved_views_notifier'; import { useSourceContext } from '../containers/metrics_source'; +import { useKibanaContextForPlugin } from './use_kibana'; export type UseMetricsExplorerViewsResult = SavedViewResult< MetricsExplorerView, @@ -44,6 +44,11 @@ const queryKeys = { export const useMetricsExplorerViews = (): UseMetricsExplorerViewsResult => { const { metricsExplorerViews } = useKibanaContextForPlugin().services; + + if (metricsExplorerViews === undefined) { + throw new Error('MetricsExplorerViews service has not been initialized.'); + } + const trackMetric = useUiTracker({ app: 'infra_metrics' }); const queryClient = useQueryClient(); diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/search_bar/unified_search_bar.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/search_bar/unified_search_bar.tsx index ea5f25880f7d2..83a30e1d84412 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/search_bar/unified_search_bar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/search_bar/unified_search_bar.tsx @@ -57,7 +57,11 @@ export const UnifiedSearchBar = () => { defaultMessage: 'Search hosts (E.g. cloud.provider:gcp AND system.load.1 > 0.5)', })} onQuerySubmit={handleRefresh} - showSaveQuery={Boolean(application?.capabilities?.visualize?.saveQuery)} + saveQueryMenuVisibility={ + application?.capabilities?.visualize?.saveQuery + ? 'allowed_by_app_privilege' + : 'globally_managed' + } showDatePicker showFilterBar showQueryInput diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index 562c7a43175cc..d0e41a68446a6 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -8,7 +8,6 @@ import { i18n } from '@kbn/i18n'; import React, { useContext } from 'react'; -import { RouteComponentProps } from 'react-router-dom'; import { Routes, Route } from '@kbn/shared-ux-router'; import { EuiErrorBoundary, EuiHeaderLinks, EuiHeaderLink } from '@elastic/eui'; @@ -37,12 +36,14 @@ import { HeaderActionMenuContext } from '../../utils/header_action_menu_provider import { CreateDerivedIndexPattern, useSourceContext } from '../../containers/metrics_source'; import { NotFoundPage } from '../404'; import { ReactQueryProvider } from '../../containers/react_query_provider'; +import { usePluginConfig } from '../../containers/plugin_config_context'; const ADD_DATA_LABEL = i18n.translate('xpack.infra.metricsHeaderAddDataButtonLabel', { defaultMessage: 'Add data', }); -export const InfrastructurePage = ({ match }: RouteComponentProps) => { +export const InfrastructurePage = () => { + const config = usePluginConfig(); const uiCapabilities = useKibana().services.application?.capabilities; const { setHeaderActionMenu, theme$ } = useContext(HeaderActionMenuContext); @@ -96,19 +97,21 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { )} - - - - {source?.configuration ? ( - - ) : ( - - )} - - + {config.featureFlags.metricsExplorerEnabled && ( + + + + {source?.configuration ? ( + + ) : ( + + )} + + + )} @@ -131,10 +134,6 @@ const PageContent = (props: { const { createDerivedIndexPattern, configuration } = props; return ( - + ); }; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx index 4e1328fc3ae7e..b1ea933788cd2 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx @@ -23,6 +23,7 @@ import { MetricsPageTemplate } from '../page_template'; import { metricsExplorerTitle } from '../../../translations'; import { DerivedIndexPattern } from '../../../containers/metrics_source'; import { SavedViews } from './components/saved_views'; + interface MetricsExplorerPageProps { source: MetricsSourceConfigurationProperties; derivedIndexPattern: DerivedIndexPattern; diff --git a/x-pack/plugins/infra/public/plugin.ts b/x-pack/plugins/infra/public/plugin.ts index 0bcdfa7e04bcc..b5c719be216f7 100644 --- a/x-pack/plugins/infra/public/plugin.ts +++ b/x-pack/plugins/infra/public/plugin.ts @@ -50,7 +50,7 @@ import { getLogsHasDataFetcher, getLogsOverviewDataFetcher } from './utils/logs_ export class Plugin implements InfraClientPluginClass { public config: InfraPublicConfig; private inventoryViews: InventoryViewsService; - private metricsExplorerViews: MetricsExplorerViewsService; + private metricsExplorerViews?: MetricsExplorerViewsService; private telemetry: TelemetryService; private locators?: InfraLocators; private kibanaVersion: string; @@ -60,7 +60,9 @@ export class Plugin implements InfraClientPluginClass { this.config = context.config.get(); this.inventoryViews = new InventoryViewsService(); - this.metricsExplorerViews = new MetricsExplorerViewsService(); + this.metricsExplorerViews = this.config.featureFlags.metricsExplorerEnabled + ? new MetricsExplorerViewsService() + : undefined; this.telemetry = new TelemetryService(); this.kibanaVersion = context.env.packageInfo.version; } @@ -105,7 +107,9 @@ export class Plugin implements InfraClientPluginClass { /** !! Need to be kept in sync with the deepLinks in x-pack/plugins/infra/public/plugin.ts */ const infraEntries = [ { label: 'Inventory', app: 'metrics', path: '/inventory' }, - { label: 'Metrics Explorer', app: 'metrics', path: '/explorer' }, + ...(this.config.featureFlags.metricsExplorerEnabled + ? [{ label: 'Metrics Explorer', app: 'metrics', path: '/explorer' }] + : []), { label: 'Hosts', isBetaFeature: true, app: 'metrics', path: '/hosts' }, ]; pluginsSetup.observabilityShared.navigation.registerSections( @@ -231,13 +235,17 @@ export class Plugin implements InfraClientPluginClass { }), path: '/hosts', }, - { - id: 'metrics-explorer', - title: i18n.translate('xpack.infra.homePage.metricsExplorerTabTitle', { - defaultMessage: 'Metrics Explorer', - }), - path: '/explorer', - }, + ...(this.config.featureFlags.metricsExplorerEnabled + ? [ + { + id: 'metrics-explorer', + title: i18n.translate('xpack.infra.homePage.metricsExplorerTabTitle', { + defaultMessage: 'Metrics Explorer', + }), + path: '/explorer', + }, + ] + : []), { id: 'settings', title: i18n.translate('xpack.infra.homePage.settingsTabTitle', { @@ -266,6 +274,7 @@ export class Plugin implements InfraClientPluginClass { coreStart, { ...plugins, kibanaVersion: this.kibanaVersion }, pluginStart, + this.config, params ); }, @@ -313,7 +322,7 @@ export class Plugin implements InfraClientPluginClass { http: core.http, }); - const metricsExplorerViews = this.metricsExplorerViews.start({ + const metricsExplorerViews = this.metricsExplorerViews?.start({ http: core.http, }); diff --git a/x-pack/plugins/infra/public/types.ts b/x-pack/plugins/infra/public/types.ts index c663f57592f52..bbd2852ce00fe 100644 --- a/x-pack/plugins/infra/public/types.ts +++ b/x-pack/plugins/infra/public/types.ts @@ -62,7 +62,7 @@ export interface InfraClientSetupExports { export interface InfraClientStartExports { inventoryViews: InventoryViewsServiceStart; - metricsExplorerViews: MetricsExplorerViewsServiceStart; + metricsExplorerViews?: MetricsExplorerViewsServiceStart; telemetry: ITelemetryClient; locators: InfraLocators; ContainerMetricsTable: ( diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts index c10987b75c43b..3b8b6ada30232 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -34,6 +34,7 @@ interface FrozenIndexParams { export class KibanaFramework { public router: IRouter; public plugins: InfraServerPluginSetupDeps; + public config: InfraConfig; private core: CoreSetup; constructor( @@ -44,6 +45,7 @@ export class KibanaFramework { this.router = core.http.createRouter(); this.plugins = plugins; this.core = core; + this.config = config; } public registerRoute( diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 6eec0c9f28629..c28245ececfef 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -1898,6 +1898,9 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({ inventory: { compositeSize: 2000, }, + featureFlags: { + metricsExplorerEnabled: true, + }, enabled: true, sources, }); diff --git a/x-pack/plugins/infra/server/lib/sources/sources.test.ts b/x-pack/plugins/infra/server/lib/sources/sources.test.ts index 183ce952583a0..b149838c82b32 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.test.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.test.ts @@ -125,6 +125,9 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({ inventory: { compositeSize: 2000, }, + featureFlags: { + metricsExplorerEnabled: true, + }, sources, enabled: true, }); diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 10bf7e37fb7c6..50e0779928ecd 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -6,7 +6,7 @@ */ import { Server } from '@hapi/hapi'; -import { schema } from '@kbn/config-schema'; +import { schema, offeringBasedSchema } from '@kbn/config-schema'; import { CoreStart, Plugin, @@ -80,6 +80,12 @@ export const config: PluginConfigDescriptor = { ), }) ), + featureFlags: schema.object({ + metricsExplorerEnabled: offeringBasedSchema({ + traditional: schema.boolean({ defaultValue: true }), + serverless: schema.boolean({ defaultValue: false }), + }), + }), }), deprecations: configDeprecations, exposeToBrowser: publicConfigKeys, @@ -111,7 +117,7 @@ export class InfraServerPlugin private logsRules: RulesService; private metricsRules: RulesService; private inventoryViews: InventoryViewsService; - private metricsExplorerViews: MetricsExplorerViewsService; + private metricsExplorerViews?: MetricsExplorerViewsService; constructor(context: PluginInitializerContext) { this.config = context.config.get(); @@ -129,9 +135,9 @@ export class InfraServerPlugin ); this.inventoryViews = new InventoryViewsService(this.logger.get('inventoryViews')); - this.metricsExplorerViews = new MetricsExplorerViewsService( - this.logger.get('metricsExplorerViews') - ); + this.metricsExplorerViews = this.config.featureFlags.metricsExplorerEnabled + ? new MetricsExplorerViewsService(this.logger.get('metricsExplorerViews')) + : undefined; } setup(core: InfraPluginCoreSetup, plugins: InfraServerPluginSetupDeps) { @@ -155,12 +161,14 @@ export class InfraServerPlugin // Setup infra services const inventoryViews = this.inventoryViews.setup(); - const metricsExplorerViews = this.metricsExplorerViews.setup(); + const metricsExplorerViews = this.metricsExplorerViews?.setup(); // Register saved object types core.savedObjects.registerType(infraSourceConfigurationSavedObjectType); core.savedObjects.registerType(inventoryViewSavedObjectType); - core.savedObjects.registerType(metricsExplorerViewSavedObjectType); + if (this.config.featureFlags.metricsExplorerEnabled) { + core.savedObjects.registerType(metricsExplorerViewSavedObjectType); + } // TODO: separate these out individually and do away with "domains" as a temporary group // and make them available via the request context so we can do away with @@ -255,7 +263,7 @@ export class InfraServerPlugin savedObjects: core.savedObjects, }); - const metricsExplorerViews = this.metricsExplorerViews.start({ + const metricsExplorerViews = this.metricsExplorerViews?.start({ infraSources: this.libs.sources, savedObjects: core.savedObjects, }); diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer_views/create_metrics_explorer_view.ts b/x-pack/plugins/infra/server/routes/metrics_explorer_views/create_metrics_explorer_view.ts index d02ed1208eb11..45ff1010a9027 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer_views/create_metrics_explorer_view.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer_views/create_metrics_explorer_view.ts @@ -15,6 +15,13 @@ import { } from '../../../common/http_api/latest'; import type { InfraBackendLibs } from '../../lib/infra_types'; +const NON_STARTED_SERVICE_ERROR = { + statusCode: 500, + body: { + message: `Handler for "POST ${METRICS_EXPLORER_VIEW_URL}" was registered but MetricsViewService has not started.`, + }, +}; + export const initCreateMetricsExplorerViewRoute = ({ framework, getStartServices, @@ -31,6 +38,11 @@ export const initCreateMetricsExplorerViewRoute = ({ async (_requestContext, request, response) => { const { body, query } = request; const [, , { metricsExplorerViews }] = await getStartServices(); + + if (metricsExplorerViews === undefined) { + return response.customError(NON_STARTED_SERVICE_ERROR); + } + const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request); try { diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer_views/delete_metrics_explorer_view.ts b/x-pack/plugins/infra/server/routes/metrics_explorer_views/delete_metrics_explorer_view.ts index a3b6f8b05f099..05e5723ded707 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer_views/delete_metrics_explorer_view.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer_views/delete_metrics_explorer_view.ts @@ -13,6 +13,13 @@ import { } from '../../../common/http_api/latest'; import type { InfraBackendLibs } from '../../lib/infra_types'; +const NON_STARTED_SERVICE_ERROR = { + statusCode: 500, + body: { + message: `Handler for "DELETE ${METRICS_EXPLORER_VIEW_URL_ENTITY}" was registered but MetricsViewService has not started.`, + }, +}; + export const initDeleteMetricsExplorerViewRoute = ({ framework, getStartServices, @@ -28,6 +35,11 @@ export const initDeleteMetricsExplorerViewRoute = ({ async (_requestContext, request, response) => { const { params } = request; const [, , { metricsExplorerViews }] = await getStartServices(); + + if (metricsExplorerViews === undefined) { + return response.customError(NON_STARTED_SERVICE_ERROR); + } + const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request); try { diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer_views/find_metrics_explorer_view.ts b/x-pack/plugins/infra/server/routes/metrics_explorer_views/find_metrics_explorer_view.ts index fbae7790b04eb..d915b545de1ee 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer_views/find_metrics_explorer_view.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer_views/find_metrics_explorer_view.ts @@ -13,6 +13,13 @@ import { } from '../../../common/http_api/latest'; import type { InfraBackendLibs } from '../../lib/infra_types'; +const NON_STARTED_SERVICE_ERROR = { + statusCode: 500, + body: { + message: `Handler for "GET ${METRICS_EXPLORER_VIEW_URL}" was registered but MetricsViewService has not started.`, + }, +}; + export const initFindMetricsExplorerViewRoute = ({ framework, getStartServices, @@ -28,6 +35,11 @@ export const initFindMetricsExplorerViewRoute = ({ async (_requestContext, request, response) => { const { query } = request; const [, , { metricsExplorerViews }] = await getStartServices(); + + if (metricsExplorerViews === undefined) { + return response.customError(NON_STARTED_SERVICE_ERROR); + } + const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request); try { diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer_views/get_metrics_explorer_view.ts b/x-pack/plugins/infra/server/routes/metrics_explorer_views/get_metrics_explorer_view.ts index b8e71a3c662d6..7582bf22d80e5 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer_views/get_metrics_explorer_view.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer_views/get_metrics_explorer_view.ts @@ -15,6 +15,13 @@ import { } from '../../../common/http_api/latest'; import type { InfraBackendLibs } from '../../lib/infra_types'; +const NON_STARTED_SERVICE_ERROR = { + statusCode: 500, + body: { + message: `Handler for "GET ${METRICS_EXPLORER_VIEW_URL_ENTITY}" was registered but MetricsViewService has not started.`, + }, +}; + export const initGetMetricsExplorerViewRoute = ({ framework, getStartServices, @@ -31,6 +38,11 @@ export const initGetMetricsExplorerViewRoute = ({ async (_requestContext, request, response) => { const { params, query } = request; const [, , { metricsExplorerViews }] = await getStartServices(); + + if (metricsExplorerViews === undefined) { + return response.customError(NON_STARTED_SERVICE_ERROR); + } + const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request); try { diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer_views/index.ts b/x-pack/plugins/infra/server/routes/metrics_explorer_views/index.ts index e4a6165374422..ae95dc9c43c26 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer_views/index.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer_views/index.ts @@ -15,6 +15,10 @@ import { initUpdateMetricsExplorerViewRoute } from './update_metrics_explorer_vi export const initMetricsExplorerViewRoutes = ( dependencies: Pick ) => { + if (!dependencies.framework.config.featureFlags.metricsExplorerEnabled) { + return; + } + initCreateMetricsExplorerViewRoute(dependencies); initDeleteMetricsExplorerViewRoute(dependencies); initFindMetricsExplorerViewRoute(dependencies); diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer_views/update_metrics_explorer_view.ts b/x-pack/plugins/infra/server/routes/metrics_explorer_views/update_metrics_explorer_view.ts index ebd8caef8e030..fc7f8ecd78930 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer_views/update_metrics_explorer_view.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer_views/update_metrics_explorer_view.ts @@ -16,6 +16,13 @@ import { } from '../../../common/http_api/latest'; import type { InfraBackendLibs } from '../../lib/infra_types'; +const NON_STARTED_SERVICE_ERROR = { + statusCode: 500, + body: { + message: `Handler for "PUT ${METRICS_EXPLORER_VIEW_URL_ENTITY}" was registered but MetricsViewService has not started.`, + }, +}; + export const initUpdateMetricsExplorerViewRoute = ({ framework, getStartServices, @@ -33,6 +40,11 @@ export const initUpdateMetricsExplorerViewRoute = ({ async (_requestContext, request, response) => { const { body, params, query } = request; const [, , { metricsExplorerViews }] = await getStartServices(); + + if (metricsExplorerViews === undefined) { + return response.customError(NON_STARTED_SERVICE_ERROR); + } + const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request); try { diff --git a/x-pack/plugins/infra/server/types.ts b/x-pack/plugins/infra/server/types.ts index e9d9faa548bb2..8fc3576027d64 100644 --- a/x-pack/plugins/infra/server/types.ts +++ b/x-pack/plugins/infra/server/types.ts @@ -27,12 +27,12 @@ export interface InfraPluginSetup { sourceProperties: InfraStaticSourceConfiguration ) => void; inventoryViews: InventoryViewsServiceSetup; - metricsExplorerViews: MetricsExplorerViewsServiceSetup; + metricsExplorerViews?: MetricsExplorerViewsServiceSetup; } export interface InfraPluginStart { inventoryViews: InventoryViewsServiceStart; - metricsExplorerViews: MetricsExplorerViewsServiceStart; + metricsExplorerViews?: MetricsExplorerViewsServiceStart; } export type MlSystem = ReturnType; diff --git a/x-pack/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/plugins/lens/public/app_plugin/app.test.tsx index 30311af0ba431..9f5a9eb6d5a46 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.test.tsx @@ -930,6 +930,38 @@ describe('Lens App', () => { instance.update(); expect(instance.find(SavedObjectSaveModal).prop('showCopyOnSave')).toEqual(false); }); + + it('enables Save Query UI when user has app-level permissions', async () => { + const services = makeDefaultServicesForApp(); + services.application = { + ...services.application, + capabilities: { + ...services.application.capabilities, + visualize: { saveQuery: true }, + }, + }; + const { instance } = await mountWith({ services }); + await act(async () => { + const topNavMenu = instance.find(services.navigation.ui.AggregateQueryTopNavMenu); + expect(topNavMenu.props().saveQueryMenuVisibility).toBe('allowed_by_app_privilege'); + }); + }); + + it('checks global save query permission when user does not have app-level permissions', async () => { + const services = makeDefaultServicesForApp(); + services.application = { + ...services.application, + capabilities: { + ...services.application.capabilities, + visualize: { saveQuery: false }, + }, + }; + const { instance } = await mountWith({ services }); + await act(async () => { + const topNavMenu = instance.find(services.navigation.ui.AggregateQueryTopNavMenu); + expect(topNavMenu.props().saveQueryMenuVisibility).toBe('globally_managed'); + }); + }); }); }); @@ -1187,7 +1219,7 @@ describe('Lens App', () => { }; await mountWith({ services }); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( - expect.objectContaining({ showSaveQuery: false }), + expect.objectContaining({ saveQueryMenuVisibility: 'globally_managed' }), {} ); }); @@ -1196,7 +1228,7 @@ describe('Lens App', () => { const { instance, services } = await mountWith({}); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ - showSaveQuery: true, + saveQueryMenuVisibility: 'allowed_by_app_privilege', savedQuery: undefined, onSaved: expect.any(Function), onSavedQueryUpdated: expect.any(Function), diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index dc4707a809bc9..3a285ec4f33c8 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -1054,7 +1054,11 @@ export const LensTopNavMenu = ({ { showSearchBar={true} showFilterBar={true} showDatePicker={true} - showSaveQuery={!!getMapsCapabilities().saveQuery} + saveQueryMenuVisibility={ + getMapsCapabilities().saveQuery ? 'allowed_by_app_privilege' : 'globally_managed' + } savedQuery={this.state.savedQuery} onSaved={this._updateStateFromSavedQuery} onSavedQueryUpdated={this._updateStateFromSavedQuery} diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts index 47976f3740c76..b3053fc11bc9f 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts @@ -25,120 +25,128 @@ import { } from '../../tasks/live_query'; import { generateRandomStringName, interceptCaseId } from '../../tasks/integrations'; import { ServerlessRoleName } from '../../support/roles'; -describe('Alert Event Details - Cases', { tags: ['@ess', '@serverless'] }, () => { - let ruleId: string; - let ruleName: string; - let packId: string; - let packName: string; - const packData = packFixture(); - before(() => { - loadPack(packData).then((data) => { - packId = data.saved_object_id; - packName = data.name; - }); - loadRule(true).then((data) => { - ruleId = data.id; - ruleName = data.name; - loadRuleAlerts(data.name); - }); - }); - - beforeEach(() => { - cy.login(ServerlessRoleName.SOC_MANAGER); - cy.visit('/app/security/rules'); - clickRuleName(ruleName); - }); - - after(() => { - cleanupPack(packId); - cleanupRule(ruleId); - }); - - describe('Case creation', () => { - let caseId: string; +describe( + 'Alert Event Details - Cases', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + let ruleId: string; + let ruleName: string; + let packId: string; + let packName: string; + const packData = packFixture(); before(() => { - interceptCaseId((id) => { - caseId = id; + loadPack(packData).then((data) => { + packId = data.saved_object_id; + packName = data.name; + }); + loadRule(true).then((data) => { + ruleId = data.id; + ruleName = data.name; + loadRuleAlerts(data.name); }); }); + beforeEach(() => { + cy.login(ServerlessRoleName.SOC_MANAGER); + cy.visit('/app/security/rules'); + clickRuleName(ruleName); + }); + after(() => { - cleanupCase(caseId); + cleanupPack(packId); + cleanupRule(ruleId); }); - it('runs osquery against alert and creates a new case', () => { - const [caseName, caseDescription] = generateRandomStringName(2); - cy.getBySel('expand-event').first().click({ force: true }); - cy.getBySel('take-action-dropdown-btn').click(); - cy.getBySel('osquery-action-item').click(); - cy.contains(/^\d+ agen(t|ts) selected/); - cy.contains('Run a set of queries in a pack').click(); - cy.get(LIVE_QUERY_EDITOR).should('not.exist'); - cy.getBySel('select-live-pack').click().type(`${packName}{downArrow}{enter}`); - submitQuery(); - cy.get('[aria-label="Add to Case"]').first().click(); - cy.getBySel('cases-table-add-case-filter-bar').click(); - cy.getBySel('create-case-flyout').should('be.visible'); - cy.getBySel('caseTitle').within(() => { - cy.getBySel('input').type(caseName); + describe('Case creation', () => { + let caseId: string; + + before(() => { + interceptCaseId((id) => { + caseId = id; + }); }); - cy.getBySel('caseDescription').within(() => { - cy.getBySel('euiMarkdownEditorTextArea').type(caseDescription); + + after(() => { + cleanupCase(caseId); + }); + + it('runs osquery against alert and creates a new case', () => { + const [caseName, caseDescription] = generateRandomStringName(2); + cy.getBySel('expand-event').first().click({ force: true }); + cy.getBySel('take-action-dropdown-btn').click(); + cy.getBySel('osquery-action-item').click(); + cy.contains(/^\d+ agen(t|ts) selected/); + cy.contains('Run a set of queries in a pack').click(); + cy.get(LIVE_QUERY_EDITOR).should('not.exist'); + cy.getBySel('select-live-pack').click().type(`${packName}{downArrow}{enter}`); + submitQuery(); + cy.get('[aria-label="Add to Case"]').first().click(); + cy.getBySel('cases-table-add-case-filter-bar').click(); + cy.getBySel('create-case-flyout').should('be.visible'); + cy.getBySel('caseTitle').within(() => { + cy.getBySel('input').type(caseName); + }); + cy.getBySel('caseDescription').within(() => { + cy.getBySel('euiMarkdownEditorTextArea').type(caseDescription); + }); + cy.getBySel('create-case-submit').click(); + cy.contains(`An alert was added to "${caseName}"`); }); - cy.getBySel('create-case-submit').click(); - cy.contains(`An alert was added to "${caseName}"`); }); - }); - // verify why calling new action doesnt add to response actions list - describe.skip('Case', () => { - let caseId: string; + // verify why calling new action doesnt add to response actions list + describe.skip('Case', () => { + let caseId: string; - before(() => { - loadCase('securitySolution').then((data) => { - caseId = data.id; + before(() => { + loadCase('securitySolution').then((data) => { + caseId = data.id; + }); }); - }); - after(() => { - cleanupCase(caseId); - }); + after(() => { + cleanupCase(caseId); + }); - it('sees osquery results from last action and add to a case', () => { - cy.getBySel('expand-event').first().click(); - cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click(); - cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click(); - cy.getBySel('responseActionsViewWrapper').should('exist'); - cy.contains('select * from users;'); - cy.contains("SELECT * FROM os_version where name='Ubuntu';"); - cy.getBySel('osquery-results-comment').each(($comment) => { - cy.wrap($comment).within(() => { - // On initial load result table might not render due to displayed error - if ($comment.find('div .euiDataGridRow').length <= 0) { - // If tabs are present try clicking between status and results to get rid of the error message - if ($comment.find('div .euiTabs').length > 0) { - cy.getBySel('osquery-status-tab').click(); - cy.getBySel('osquery-results-tab').click(); + it('sees osquery results from last action and add to a case', () => { + cy.getBySel('expand-event').first().click(); + cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click(); + cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click(); + cy.getBySel('responseActionsViewWrapper').should('exist'); + cy.contains('select * from users;'); + cy.contains("SELECT * FROM os_version where name='Ubuntu';"); + cy.getBySel('osquery-results-comment').each(($comment) => { + cy.wrap($comment).within(() => { + // On initial load result table might not render due to displayed error + if ($comment.find('div .euiDataGridRow').length <= 0) { + // If tabs are present try clicking between status and results to get rid of the error message + if ($comment.find('div .euiTabs').length > 0) { + cy.getBySel('osquery-status-tab').click(); + cy.getBySel('osquery-results-tab').click(); + cy.getBySel('dataGridRowCell', { timeout: 120000 }).should( + 'have.lengthOf.above', + 0 + ); + } + } else { + // Result tab was rendered successfully cy.getBySel('dataGridRowCell', { timeout: 120000 }).should('have.lengthOf.above', 0); } - } else { - // Result tab was rendered successfully - cy.getBySel('dataGridRowCell', { timeout: 120000 }).should('have.lengthOf.above', 0); - } - // } + // } + }); + }); + checkActionItemsInResults({ + lens: true, + discover: true, + cases: true, + timeline: true, }); - }); - checkActionItemsInResults({ - lens: true, - discover: true, - cases: true, - timeline: true, - }); - addToCase(caseId); - viewRecentCaseAndCheckResults(); + addToCase(caseId); + viewRecentCaseAndCheckResults(); + }); }); - }); -}); + } +); diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_liked_apps.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_liked_apps.cy.ts index 76850020d74ff..19774d956a303 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_liked_apps.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_liked_apps.cy.ts @@ -20,6 +20,7 @@ import { ServerlessRoleName } from '../../support/roles'; const UUID_REGEX = '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}'; +// Issue: https://github.com/elastic/security-team/issues/7731 describe.skip('Alert Event Details', { tags: ['@ess', '@serverless'] }, () => { let ruleId: string; let ruleName: string; diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts index c56eb97a02050..d9be2632bdca2 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts @@ -15,93 +15,97 @@ import { } from '../../tasks/live_query'; import { ServerlessRoleName } from '../../support/roles'; -describe('Alert Event Details - dynamic params', { tags: ['@ess', '@serverless'] }, () => { - let ruleId: string; - let ruleName: string; +describe( + 'Alert Event Details - dynamic params', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + let ruleId: string; + let ruleName: string; - before(() => { - loadRule(true).then((data) => { - ruleId = data.id; - ruleName = data.name; - loadRuleAlerts(data.name); + before(() => { + loadRule(true).then((data) => { + ruleId = data.id; + ruleName = data.name; + loadRuleAlerts(data.name); + }); }); - }); - - after(() => { - cleanupRule(ruleId); - }); - - beforeEach(() => { - cy.login(ServerlessRoleName.SOC_MANAGER); - cy.visit('/app/security/rules'); - clickRuleName(ruleName); - }); - it('should substitute parameters in investigation guide', () => { - cy.getBySel('expand-event').first().click(); - cy.getBySel('securitySolutionFlyoutInvestigationGuideButton').click(); - cy.contains('Get processes').click(); - cy.getBySel('flyout-body-osquery').within(() => { - cy.contains("SELECT * FROM os_version where name='Ubuntu';"); - cy.contains('host.os.platform'); - cy.contains('platform'); + after(() => { + cleanupRule(ruleId); }); - }); - // response-actions-notification doesn't exist in expandable flyout - it.skip('should substitute parameters in live query and increase number of ran queries', () => { - let initialNotificationCount: number; - let updatedNotificationCount: number; - cy.getBySel('expand-event').first().click(); - cy.getBySel('response-actions-notification') - .should('not.have.text', '0') - .then((element) => { - initialNotificationCount = parseInt(element.text(), 10); - }); - takeOsqueryActionWithParams(); - cy.getBySel('osquery-empty-button').click(); - cy.getBySel('response-actions-notification') - .should('not.have.text', '0') - .then((element) => { - updatedNotificationCount = parseInt(element.text(), 10); - expect(initialNotificationCount).to.be.equal(updatedNotificationCount - 1); - }) - .then(() => { - cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click(); - cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click(); - cy.getBySel('responseActionsViewWrapper').within(() => { - cy.contains('tags'); - cy.getBySel('osquery-results-comment').should('have.length', updatedNotificationCount); - }); - }); + beforeEach(() => { + cy.login(ServerlessRoleName.SOC_MANAGER); + cy.visit('/app/security/rules'); + clickRuleName(ruleName); + }); - it('should be able to run take action query against all enrolled agents', () => { + it('should substitute parameters in investigation guide', () => { cy.getBySel('expand-event').first().click(); - cy.getBySel('take-action-dropdown-btn').click(); - cy.getBySel('osquery-action-item').click(); - cy.getBySel('agentSelection').within(() => { - cy.getBySel('comboBoxClearButton').click(); - cy.getBySel('comboBoxInput').type('All{downArrow}{enter}{esc}'); - cy.contains('All agents'); - }); - inputQuery("SELECT * FROM os_version where name='{{host.os.name}}';", { - parseSpecialCharSequences: false, - }); - cy.wait(1000); - submitQuery(); + cy.getBySel('securitySolutionFlyoutInvestigationGuideButton').click(); + cy.contains('Get processes').click(); cy.getBySel('flyout-body-osquery').within(() => { - // at least 2 agents should have responded, sometimes it takes a while for the agents to respond - cy.get('[data-grid-row-index]', { timeout: 6000000 }).should('have.length.at.least', 2); + cy.contains("SELECT * FROM os_version where name='Ubuntu';"); + cy.contains('host.os.platform'); + cy.contains('platform'); }); }); - it('should substitute params in osquery ran from timelines alerts', () => { - loadRuleAlerts(ruleName); - cy.getBySel('send-alert-to-timeline-button').first().click(); - cy.getBySel('query-events-table').within(() => { + // response-actions-notification doesn't exist in expandable flyout + it.skip('should substitute parameters in live query and increase number of ran queries', () => { + let initialNotificationCount: number; + let updatedNotificationCount: number; + cy.getBySel('expand-event').first().click(); + cy.getBySel('response-actions-notification') + .should('not.have.text', '0') + .then((element) => { + initialNotificationCount = parseInt(element.text(), 10); + }); + takeOsqueryActionWithParams(); + cy.getBySel('osquery-empty-button').click(); + cy.getBySel('response-actions-notification') + .should('not.have.text', '0') + .then((element) => { + updatedNotificationCount = parseInt(element.text(), 10); + expect(initialNotificationCount).to.be.equal(updatedNotificationCount - 1); + }) + .then(() => { + cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseSectionHeader').click(); + cy.getBySel('securitySolutionDocumentDetailsFlyoutResponseButton').click(); + cy.getBySel('responseActionsViewWrapper').within(() => { + cy.contains('tags'); + cy.getBySel('osquery-results-comment').should('have.length', updatedNotificationCount); + }); + }); + + it('should be able to run take action query against all enrolled agents', () => { cy.getBySel('expand-event').first().click(); + cy.getBySel('take-action-dropdown-btn').click(); + cy.getBySel('osquery-action-item').click(); + cy.getBySel('agentSelection').within(() => { + cy.getBySel('comboBoxClearButton').click(); + cy.getBySel('comboBoxInput').type('All{downArrow}{enter}{esc}'); + cy.contains('All agents'); + }); + inputQuery("SELECT * FROM os_version where name='{{host.os.name}}';", { + parseSpecialCharSequences: false, + }); + cy.wait(1000); + submitQuery(); + cy.getBySel('flyout-body-osquery').within(() => { + // at least 2 agents should have responded, sometimes it takes a while for the agents to respond + cy.get('[data-grid-row-index]', { timeout: 6000000 }).should('have.length.at.least', 2); + }); + }); + + it('should substitute params in osquery ran from timelines alerts', () => { + loadRuleAlerts(ruleName); + cy.getBySel('send-alert-to-timeline-button').first().click(); + cy.getBySel('query-events-table').within(() => { + cy.getBySel('expand-event').first().click(); + }); + takeOsqueryActionWithParams(); }); - takeOsqueryActionWithParams(); }); - }); -}); + } +); diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts index 95661cd848470..cd7f70a3ac9c3 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts @@ -28,6 +28,7 @@ import { import { closeDateTabIfVisible, closeToastIfVisible } from '../../tasks/integrations'; import { ServerlessRoleName } from '../../support/roles'; +// Issue: https://github.com/elastic/security-team/issues/7731 describe.skip( 'Alert Event Details - Response Actions Form', { tags: ['@ess', '@serverless'] }, diff --git a/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts index f1893e5e5a16f..2a920ef22ef6a 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts @@ -18,7 +18,7 @@ import { LIVE_QUERY_EDITOR } from '../../screens/live_query'; import { getAdvancedButton } from '../../screens/integrations'; import { ServerlessRoleName } from '../../support/roles'; -describe('ALL - Live Query', { tags: ['@serverless', '@ess'] }, () => { +describe('ALL - Live Query', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { cy.login(ServerlessRoleName.SOC_MANAGER); navigateTo('/app/osquery'); diff --git a/x-pack/plugins/osquery/cypress/e2e/all/live_query_packs.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/live_query_packs.cy.ts index fb5566ba3c393..cc6a367668b08 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/live_query_packs.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/live_query_packs.cy.ts @@ -18,7 +18,7 @@ import { LIVE_QUERY_EDITOR } from '../../screens/live_query'; import { loadPack, cleanupPack, cleanupCase, loadCase } from '../../tasks/api_fixtures'; import { ServerlessRoleName } from '../../support/roles'; -describe('ALL - Live Query Packs', { tags: ['@serverless', '@ess'] }, () => { +describe('ALL - Live Query Packs', { tags: ['@ess', '@serverless'] }, () => { let packName: string; let packId: string; let caseId: string; @@ -75,7 +75,6 @@ describe('ALL - Live Query Packs', { tags: ['@serverless', '@ess'] }, () => { cy.contains('failingQuery'); selectAllAgents(); submitQuery(); - cy.getBySel('live-query-loading').should('exist'); cy.getBySel('toggleIcon-system_memory_linux_elastic').click(); checkResults(); checkActionItemsInResults({ diff --git a/x-pack/plugins/osquery/cypress/e2e/all/packs_create_edit.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/packs_create_edit.cy.ts index 770d5afc5ec0f..ca093c9241256 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/packs_create_edit.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/packs_create_edit.cy.ts @@ -509,70 +509,74 @@ describe('Packs - Create and Edit', () => { }); }); - describe('should verify that packs are triggered', { tags: ['@ess', '@serverless'] }, () => { - let packId: string; - let packName: string; + describe( + 'should verify that packs are triggered', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + let packId: string; + let packName: string; - before(() => { - request<{ items: PackagePolicy[] }>({ - url: '/internal/osquery/fleet_wrapper/package_policies', - headers: { - 'Elastic-Api-Version': API_VERSIONS.internal.v1, - }, - }) - .then((response) => - loadPack({ - policy_ids: [response.body.items[0].policy_id], - queries: { - [savedQueryName]: { ecs_mapping: {}, interval: 60, query: 'select * from uptime;' }, - }, - }) - ) - .then((pack) => { - packId = pack.saved_object_id; - packName = pack.name; - }); - }); + before(() => { + request<{ items: PackagePolicy[] }>({ + url: '/internal/osquery/fleet_wrapper/package_policies', + headers: { + 'Elastic-Api-Version': API_VERSIONS.internal.v1, + }, + }) + .then((response) => + loadPack({ + policy_ids: [response.body.items[0].policy_id], + queries: { + [savedQueryName]: { ecs_mapping: {}, interval: 60, query: 'select * from uptime;' }, + }, + }) + ) + .then((pack) => { + packId = pack.saved_object_id; + packName = pack.name; + }); + }); - after(() => { - cleanupPack(packId); - }); + after(() => { + cleanupPack(packId); + }); - it('', () => { - preparePack(packName); - cy.contains(`${packName} details`).should('exist'); + it('', () => { + preparePack(packName); + cy.contains(`${packName} details`).should('exist'); - recurse( - () => { - cy.getBySel('docsLoading').should('exist'); - cy.getBySel('docsLoading').should('not.exist'); + recurse( + () => { + cy.getBySel('docsLoading').should('exist'); + cy.getBySel('docsLoading').should('not.exist'); - return cy.get('tbody .euiTableRow > td:nth-child(5)').invoke('text'); - }, - (response) => response === 'Docs1', - { - timeout: 300000, - post: () => { - cy.reload(); + return cy.get('tbody .euiTableRow > td:nth-child(5)').invoke('text'); }, - } - ); + (response) => response === 'Docs1', + { + timeout: 300000, + post: () => { + cy.reload(); + }, + } + ); - cy.react('ScheduledQueryLastResults', { options: { timeout: 3000 } }) - .should('exist') - .within(() => { - cy.react('FormattedRelative'); - }); + cy.react('ScheduledQueryLastResults', { options: { timeout: 3000 } }) + .should('exist') + .within(() => { + cy.react('FormattedRelative'); + }); - cy.react('DocsColumnResults').within(() => { - cy.react('EuiNotificationBadge').contains('1'); - }); - cy.react('AgentsColumnResults').within(() => { - cy.react('EuiNotificationBadge').contains('1'); + cy.react('DocsColumnResults').within(() => { + cy.react('EuiNotificationBadge').contains('1'); + }); + cy.react('AgentsColumnResults').within(() => { + cy.react('EuiNotificationBadge').contains('1'); + }); + cy.getBySel('packResultsErrorsEmpty').should('have.length', 1); }); - cy.getBySel('packResultsErrorsEmpty').should('have.length', 1); - }); - }); + } + ); describe('delete all queries in the pack', { tags: ['@ess', '@serverless'] }, () => { let packId: string; diff --git a/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts index 15fe843139174..694a6c10ed8b1 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts @@ -160,7 +160,6 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => { cy.getBySel('select-live-pack').click().type('osquery-monitoring{downArrow}{enter}'); selectAllAgents(); submitQuery(); - cy.getBySel('live-query-loading').should('exist'); cy.getBySel('toggleIcon-events').click(); checkResults(); checkActionItemsInResults({ diff --git a/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts index 017c86ed0247b..a02d10bda2bf9 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts @@ -22,7 +22,7 @@ import { getSavedQueriesComplexTest } from '../../tasks/saved_queries'; import { loadCase, cleanupCase, loadPack, cleanupPack } from '../../tasks/api_fixtures'; import { ServerlessRoleName } from '../../support/roles'; -describe('ALL - Saved queries', { tags: ['@ess', '@serverless'] }, () => { +describe('ALL - Saved queries', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { let caseId: string; before(() => { @@ -82,6 +82,7 @@ describe('ALL - Saved queries', { tags: ['@ess', '@serverless'] }, () => { }); beforeEach(() => { + cy.login(ServerlessRoleName.SOC_MANAGER); navigateTo('/app/osquery/saved_queries'); cy.getBySel('tablePaginationPopoverButton').click(); cy.getBySel('tablePagination-50-rows').click(); diff --git a/x-pack/plugins/osquery/cypress/e2e/roles/t1_and_t2_analyst.cy.ts b/x-pack/plugins/osquery/cypress/e2e/roles/t1_and_t2_analyst.cy.ts index 6528c9b911932..3a72415dce69e 100644 --- a/x-pack/plugins/osquery/cypress/e2e/roles/t1_and_t2_analyst.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/roles/t1_and_t2_analyst.cy.ts @@ -23,9 +23,9 @@ import { } from '../../tasks/api_fixtures'; import type { ServerlessRoleName } from '../../support/roles'; -describe(`T1 and T2 analysts`, { tags: ['@ess', '@serverless'] }, () => { +describe(`T1 and T2 analysts`, { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { ['t1_analyst', 't2_analyst'].forEach((role: string) => { - describe(`${role}- READ + runSavedQueries `, { tags: ['@ess', '@serverless'] }, () => { + describe(`${role}- READ + runSavedQueries `, () => { let savedQueryName: string; let savedQueryId: string; let packName: string; diff --git a/x-pack/plugins/osquery/cypress/support/e2e.ts b/x-pack/plugins/osquery/cypress/support/e2e.ts index 760aeb80d3ee8..3ff2329a1f5b9 100644 --- a/x-pack/plugins/osquery/cypress/support/e2e.ts +++ b/x-pack/plugins/osquery/cypress/support/e2e.ts @@ -72,7 +72,17 @@ Cypress.Commands.add( () => cy.get('body').click(0, 0) // 0,0 here are the x and y coordinates ); -Cypress.Commands.add('login', login); +Cypress.Commands.add('login', (role) => { + // TODO Temporary approach to login until login with role is supported in serverless + // Cypress.Commands.add('login', login); + const isServerless = Cypress.env().IS_SERVERLESS; + + if (isServerless) { + return login.with('system_indices_superuser', 'changeme'); + } + + return login(role); +}); // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/response_actions_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/response_actions_view.tsx index c5680d943ba2d..06c9b18081aea 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/response_actions_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/response_actions_view.tsx @@ -10,6 +10,7 @@ import styled from 'styled-components'; import type { EuiTabbedContentTab } from '@elastic/eui'; import { EuiNotificationBadge, EuiSpacer } from '@elastic/eui'; import type { Ecs } from '@kbn/cases-plugin/common'; +import { FormattedMessage } from '@kbn/i18n-react'; import type { SearchHit } from '../../../../common/search_strategy'; import type { ExpandedEventFieldsObject, @@ -71,7 +72,12 @@ export const useResponseActionsView = ({ ruleName={ruleName} ecsData={ecsData} /> - ) : null} + ) : ( + + )} ); diff --git a/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx b/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx index 55571cc9dfa69..e30789bfe35bf 100644 --- a/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx @@ -329,7 +329,7 @@ export const SearchBarComponent = memo( showFilterBar={!hideFilterBar} showDatePicker={true} showQueryInput={!hideQueryInput} - showSaveQuery={true} + saveQueryMenuVisibility="allowed_by_app_privilege" dataTestSubj={dataTestSubj} /> diff --git a/x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_runner/fleet_server.ts b/x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_runner/fleet_server.ts index 60471c5c46864..ae2464487cb75 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_runner/fleet_server.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_runner/fleet_server.ts @@ -5,6 +5,12 @@ * 2.0. */ +import { + CA_TRUSTED_FINGERPRINT, + FLEET_SERVER_CERT_PATH, + FLEET_SERVER_KEY_PATH, + fleetServerDevServiceAccount, +} from '@kbn/dev-utils'; import type { AgentPolicy, CreateAgentPolicyResponse, @@ -37,6 +43,9 @@ import type { PostFleetServerHostsResponse, } from '@kbn/fleet-plugin/common/types/rest_spec/fleet_server_hosts'; import chalk from 'chalk'; +import { resolve } from 'path'; +import { SERVERLESS_NODES, verifyDockerInstalled, maybeCreateDockerNetwork } from '@kbn/es'; +import { isServerlessKibanaFlavor } from '../common/stack_services'; import type { FormattedAxiosError } from '../common/format_axios_error'; import { catchAxiosErrorFormatAndThrow } from '../common/format_axios_error'; import { isLocalhost } from '../common/is_localhost'; @@ -44,32 +53,42 @@ import { dump } from './utils'; import { fetchFleetServerUrl, waitForHostToEnroll } from '../common/fleet_services'; import { getRuntimeServices } from './runtime'; +const FLEET_SERVER_CUSTOM_CONFIG = resolve(__dirname, './fleet_server.yml'); + export const runFleetServerIfNeeded = async (): Promise< - { fleetServerContainerId: string; fleetServerAgentPolicyId: string } | undefined + { fleetServerContainerId: string; fleetServerAgentPolicyId: string | undefined } | undefined > => { let fleetServerContainerId; let fleetServerAgentPolicyId; + let serviceToken; const { log, kibana: { isLocalhost: isKibanaOnLocalhost }, + kbnClient, } = getRuntimeServices(); log.info(`Setting up fleet server (if necessary)`); log.indent(4); + const isServerless = await isServerlessKibanaFlavor(kbnClient); - try { - fleetServerAgentPolicyId = await getOrCreateFleetServerAgentPolicyId(); - const serviceToken = await generateFleetServiceToken(); + await verifyDockerInstalled(log); + await maybeCreateDockerNetwork(log); - if (isKibanaOnLocalhost) { - await configureFleetIfNeeded(); + try { + if (isServerless) { + fleetServerContainerId = await startFleetServerStandAloneWithDocker(); + } else { + fleetServerAgentPolicyId = await getOrCreateFleetServerAgentPolicyId(); + serviceToken = await generateFleetServiceToken(); + if (isKibanaOnLocalhost) { + await configureFleetIfNeeded(); + } + fleetServerContainerId = await startFleetServerWithDocker({ + policyId: fleetServerAgentPolicyId, + serviceToken, + }); } - - fleetServerContainerId = await startFleetServerWithDocker({ - policyId: fleetServerAgentPolicyId, - serviceToken, - }); } catch (error) { log.error(dump(error)); log.indent(-4); @@ -201,39 +220,29 @@ export const startFleetServerWithDocker = async ({ try { const dockerArgs = [ 'run', - '--restart', 'no', - + '--net', + 'elastic', '--add-host', 'host.docker.internal:host-gateway', - '--rm', - '--detach', - '--name', containerName, - // The container's hostname will appear in Fleet when the agent enrolls '--hostname', containerName, - '--env', 'FLEET_SERVER_ENABLE=1', - '--env', `FLEET_SERVER_ELASTICSEARCH_HOST=${esUrlWithRealIp}`, - '--env', `FLEET_SERVER_SERVICE_TOKEN=${serviceToken}`, - '--env', `FLEET_SERVER_POLICY=${policyId}`, - '--publish', `${fleetServerPort}:8220`, - `docker.elastic.co/beats/elastic-agent:${version}`, ]; @@ -278,6 +287,95 @@ export const startFleetServerWithDocker = async ({ return containerId; }; +export const startFleetServerStandAloneWithDocker = async () => { + let containerId; + const { + log, + elastic: { url: elasticUrl }, + fleetServer: { port: fleetServerPort }, + } = getRuntimeServices(); + + log.info(`Starting a new fleet server using Docker`); + log.indent(4); + const esURL = new URL(elasticUrl); + + esURL.hostname = SERVERLESS_NODES[0].name; + + const esUrlWithRealIp = esURL.toString(); + + const containerName = `dev-fleet-server.${fleetServerPort}`; + try { + const dockerArgs = [ + 'run', + '--restart', + 'no', + '--net', + 'elastic', + '--add-host', + 'host.docker.internal:host-gateway', + '--rm', + '--detach', + '--name', + containerName, + // The container's hostname will appear in Fleet when the agent enrolls + '--hostname', + containerName, + '--volume', + `${FLEET_SERVER_CERT_PATH}:/fleet-server.crt`, + '--volume', + `${FLEET_SERVER_KEY_PATH}:/fleet-server.key`, + '--env', + 'FLEET_SERVER_CERT=/fleet-server.crt', + '--env', + 'FLEET_SERVER_CERT_KEY=/fleet-server.key', + '--env', + `ELASTICSEARCH_HOSTS=${esUrlWithRealIp}`, + '--env', + `ELASTICSEARCH_SERVICE_TOKEN=${fleetServerDevServiceAccount.token}`, + '--env', + `ELASTICSEARCH_CA_TRUSTED_FINGERPRINT=${CA_TRUSTED_FINGERPRINT}`, + '--volume', + `${FLEET_SERVER_CUSTOM_CONFIG}:/etc/fleet-server.yml:ro`, + '--publish', + `${fleetServerPort}:8220`, + `docker.elastic.co/observability-ci/fleet-server:latest`, + ]; + + await execa('docker', ['kill', containerName]) + .then(() => { + log.verbose( + `Killed an existing container with name [${containerName}]. New one will be started.` + ); + }) + .catch((error) => { + log.verbose(`Attempt to kill currently running fleet-server container (if any) with name [${containerName}] was unsuccessful: + ${error} +(This is ok if one was not running already)`); + }); + + log.verbose(`docker arguments:\n${dockerArgs.join(' ')}`); + + containerId = (await execa('docker', dockerArgs)).stdout; + + log.info(`Done. Fleet Server Stand Alone is running and connected to Fleet. + Container Name: ${containerName} + Container Id: ${containerId} + + View running output: ${chalk.bold(`docker attach ---sig-proxy=false ${containerName}`)} + Shell access: ${chalk.bold(`docker exec -it ${containerName} /bin/bash`)} + Kill container: ${chalk.bold(`docker kill ${containerId}`)} +`); + } catch (error) { + log.error(dump(error)); + log.indent(-4); + throw error; + } + + log.indent(-4); + + return containerId; +}; + const configureFleetIfNeeded = async () => { const { log, kbnClient, localhostRealIp } = getRuntimeServices(); diff --git a/x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_runner/fleet_server.yml b/x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_runner/fleet_server.yml new file mode 100644 index 0000000000000..3eef6445a9eae --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/endpoint_agent_runner/fleet_server.yml @@ -0,0 +1,26 @@ +# This config is intended to be used with a stand-alone fleet-server instance for development. +output: + elasticsearch: + hosts: '${ELASTICSEARCH_HOSTS}' + service_token: '${ELASTICSEARCH_SERVICE_TOKEN}' + ssl.ca_trusted_fingerprint: '${ELASTICSEARCH_CA_TRUSTED_FINGERPRINT}' + +fleet: + agent: + id: '${FLEET_SERVER_AGENT_ID:dev-fleet-server}' + +inputs: + - type: fleet-server + policy.id: '${FLEET_SERVER_POLICY_ID:fleet-server-policy}' + server: + ssl: + enabled: true + certificate: /fleet-server.crt + key: /fleet-server.key + +logging: + to_stderr: true # Force the logging output to stderr + pretty: true + level: '${LOG_LEVEL:DEBUG}' + +http.enabled: true diff --git a/x-pack/plugins/security_solution/scripts/run_cypress/get_ftr_config.ts b/x-pack/plugins/security_solution/scripts/run_cypress/get_ftr_config.ts index 11f39f6b4a27d..670a85fae4093 100644 --- a/x-pack/plugins/security_solution/scripts/run_cypress/get_ftr_config.ts +++ b/x-pack/plugins/security_solution/scripts/run_cypress/get_ftr_config.ts @@ -6,9 +6,10 @@ */ import _ from 'lodash'; - +import { SERVERLESS_NODES } from '@kbn/es'; import { EsVersion, readConfigFile } from '@kbn/test'; import type { ToolingLog } from '@kbn/tooling-log'; +import { CA_TRUSTED_FINGERPRINT } from '@kbn/dev-utils'; import { getLocalhostRealIp } from '../endpoint/common/localhost_services'; import type { parseTestFileConfig } from './utils'; @@ -133,15 +134,23 @@ export const getFTRConfig = ({ } if (hasFleetServerArgs) { - vars.kbnTestServer.serverArgs.push( - `--xpack.fleet.agents.fleet_server.hosts=["https://${hostRealIp}:${fleetServerPort}"]` - ); - vars.kbnTestServer.serverArgs.push( - `--xpack.fleet.agents.elasticsearch.host=http://${hostRealIp}:${esPort}` - ); - if (vars.serverless) { - vars.kbnTestServer.serverArgs.push(`--xpack.fleet.internal.fleetServerStandalone=false`); + vars.kbnTestServer.serverArgs.push( + `--xpack.fleet.agents.fleet_server.hosts=["https://host.docker.internal:${fleetServerPort}"]` + ); + vars.kbnTestServer.serverArgs.push( + `--xpack.fleet.agents.elasticsearch.host=https://${SERVERLESS_NODES[0].name}:${esPort}` + ); + vars.kbnTestServer.serverArgs.push( + `--xpack.fleet.agents.elasticsearch.ca_trusted_fingerprint=${CA_TRUSTED_FINGERPRINT}` + ); + } else { + vars.kbnTestServer.serverArgs.push( + `--xpack.fleet.agents.fleet_server.hosts=["https://${hostRealIp}:${fleetServerPort}"]` + ); + vars.kbnTestServer.serverArgs.push( + `--xpack.fleet.agents.elasticsearch.host=http://${hostRealIp}:${esPort}` + ); } } diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 0eea99624d611..d88577ca21f19 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -173,6 +173,7 @@ "@kbn/content-management-plugin", "@kbn/discover-utils", "@kbn/subscription-tracking", - "@kbn/openapi-generator" + "@kbn/openapi-generator", + "@kbn/es" ] } diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/search_source_expression_form.tsx index 7117455d30cc1..c4419a780809d 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/search_source_expression_form.tsx @@ -328,7 +328,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp onClearSavedQuery={onClearSavedQuery} onSavedQueryUpdated={onSavedQuery} onSaved={onSavedQuery} - showSaveQuery + saveQueryMenuVisibility="allowed_by_app_privilege" showQueryInput showFilterBar showDatePicker={false} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx index 5e5ced6d580eb..077be38b5616a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx @@ -101,7 +101,7 @@ export function AlertsSearchBar({ onRefresh={onRefresh} showDatePicker={showDatePicker} showQueryInput={true} - showSaveQuery={true} + saveQueryMenuVisibility="allowed_by_app_privilege" showSubmitButton={showSubmitButton} submitOnBlur={submitOnBlur} onQueryChange={onSearchQueryChange} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/kql_search_bar/kql_search_bar.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/kql_search_bar/kql_search_bar.tsx index 338aeddeaad9d..87e68b7a27cc6 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/kql_search_bar/kql_search_bar.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/kql_search_bar/kql_search_bar.tsx @@ -88,7 +88,7 @@ export const KqlSearchBar = React.memo(({ onQuerySubmit }) => indexPatterns={loading || error ? NO_INDEX_PATTERNS : dataView} showAutoRefreshOnly={false} showDatePicker={false} - showSaveQuery={false} + saveQueryMenuVisibility="hidden" showQueryInput={true} showQueryMenu={false} showFilterBar={true} diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_fired.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_fired.ts index fd5a4054f0895..c2d91677af2a2 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_fired.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_fired.ts @@ -28,6 +28,9 @@ export default function ({ getService }: FtrProviderContext) { describe('Custom Threshold rule - AVG - PCT - FIRED', () => { const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default'; const ALERT_ACTION_INDEX = 'alert-action-threshold'; + // DATE_VIEW should match the index template: + // x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json + const DATE_VIEW = 'kbn-data-forge-fake_hosts'; const DATA_VIEW_ID = 'data-view-id'; let infraDataIndex: string; let actionId: string; @@ -37,9 +40,9 @@ export default function ({ getService }: FtrProviderContext) { infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); await createDataView({ supertest, - name: 'metrics-fake_hosts', + name: DATE_VIEW, id: DATA_VIEW_ID, - title: 'metrics-fake_hosts', + title: DATE_VIEW, }); }); diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts index 7f7e66d050593..d17e0a1568603 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts @@ -34,6 +34,9 @@ export default function ({ getService }: FtrProviderContext) { describe('Custom Threshold rule - CUSTOM_EQ - AVG - BYTES - FIRED', () => { const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default'; const ALERT_ACTION_INDEX = 'alert-action-threshold'; + // DATE_VIEW should match the index template: + // x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json + const DATE_VIEW = 'kbn-data-forge-fake_hosts'; const DATA_VIEW_ID = 'data-view-id'; let infraDataIndex: string; let actionId: string; @@ -43,9 +46,9 @@ export default function ({ getService }: FtrProviderContext) { infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); await createDataView({ supertest, - name: 'metrics-fake_hosts', + name: DATE_VIEW, id: DATA_VIEW_ID, - title: 'metrics-fake_hosts', + title: DATE_VIEW, }); }); diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/documents_count_fired.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/documents_count_fired.ts index 6a17340094e80..4f5a1077c22d1 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/documents_count_fired.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/documents_count_fired.ts @@ -28,6 +28,9 @@ export default function ({ getService }: FtrProviderContext) { describe('Custom Threshold rule - DOCUMENTS_COUNT - FIRED', () => { const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default'; const ALERT_ACTION_INDEX = 'alert-action-threshold'; + // DATE_VIEW should match the index template: + // x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json + const DATE_VIEW = 'kbn-data-forge-fake_hosts'; const DATA_VIEW_ID = 'data-view-id'; let infraDataIndex: string; let actionId: string; @@ -37,9 +40,9 @@ export default function ({ getService }: FtrProviderContext) { infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); await createDataView({ supertest, - name: 'metrics-fake_hosts', + name: DATE_VIEW, id: DATA_VIEW_ID, - title: 'metrics-fake_hosts', + title: DATE_VIEW, }); }); diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/group_by_fired.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/group_by_fired.ts index da18b429c45c0..01386c9bd0250 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/group_by_fired.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/group_by_fired.ts @@ -41,6 +41,9 @@ export default function ({ getService }: FtrProviderContext) { describe('Custom Threshold rule - GROUP_BY - FIRED', () => { const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default'; const ALERT_ACTION_INDEX = 'alert-action-threshold'; + // DATE_VIEW should match the index template: + // x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json + const DATE_VIEW = 'kbn-data-forge-fake_hosts'; const DATA_VIEW_ID = 'data-view-id'; let infraDataIndex: string; let actionId: string; @@ -50,9 +53,9 @@ export default function ({ getService }: FtrProviderContext) { infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); await createDataView({ supertest, - name: 'metrics-fake_hosts', + name: DATE_VIEW, id: DATA_VIEW_ID, - title: 'metrics-fake_hosts', + title: DATE_VIEW, }); }); diff --git a/x-pack/test/alerting_api_integration/observability/metric_threshold_rule.ts b/x-pack/test/alerting_api_integration/observability/metric_threshold_rule.ts index 2b727820ade70..0de7e3d600612 100644 --- a/x-pack/test/alerting_api_integration/observability/metric_threshold_rule.ts +++ b/x-pack/test/alerting_api_integration/observability/metric_threshold_rule.ts @@ -36,6 +36,12 @@ export default function ({ getService }: FtrProviderContext) { describe('alert and action creation', () => { before(async () => { + await supertest.patch(`/api/metrics/source/default`).set('kbn-xsrf', 'foo').send({ + anomalyThreshold: 50, + description: '', + metricAlias: 'kbn-data-forge*', + name: 'Default', + }); infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); actionId = await createIndexConnector({ supertest, diff --git a/x-pack/test/api_integration/apis/features/features/features.ts b/x-pack/test/api_integration/apis/features/features/features.ts index a80a39e4af5dc..088b179f625d8 100644 --- a/x-pack/test/api_integration/apis/features/features/features.ts +++ b/x-pack/test/api_integration/apis/features/features/features.ts @@ -110,6 +110,7 @@ export default function ({ getService }: FtrProviderContext) { 'observabilityAIAssistant', 'observabilityCases', 'savedObjectsManagement', + 'savedQueryManagement', 'savedObjectsTagging', 'ml', 'apm', diff --git a/x-pack/test/api_integration/apis/security/privileges.ts b/x-pack/test/api_integration/apis/security/privileges.ts index c786a41411a5b..81cceb6561bd6 100644 --- a/x-pack/test/api_integration/apis/security/privileges.ts +++ b/x-pack/test/api_integration/apis/security/privileges.ts @@ -82,6 +82,7 @@ export default function ({ getService }: FtrProviderContext) { advancedSettings: ['all', 'read', 'minimal_all', 'minimal_read'], indexPatterns: ['all', 'read', 'minimal_all', 'minimal_read'], savedObjectsManagement: ['all', 'read', 'minimal_all', 'minimal_read'], + savedQueryManagement: ['all', 'minimal_all'], osquery: [ 'all', 'read', diff --git a/x-pack/test/api_integration/apis/security/privileges_basic.ts b/x-pack/test/api_integration/apis/security/privileges_basic.ts index 6c6d32c1cb1e9..174ac2a3c8f66 100644 --- a/x-pack/test/api_integration/apis/security/privileges_basic.ts +++ b/x-pack/test/api_integration/apis/security/privileges_basic.ts @@ -27,6 +27,7 @@ export default function ({ getService }: FtrProviderContext) { advancedSettings: ['all', 'read', 'minimal_all', 'minimal_read'], indexPatterns: ['all', 'read', 'minimal_all', 'minimal_read'], savedObjectsManagement: ['all', 'read', 'minimal_all', 'minimal_read'], + savedQueryManagement: ['all', 'minimal_all'], savedObjectsTagging: ['all', 'read', 'minimal_all', 'minimal_read'], graph: ['all', 'read', 'minimal_all', 'minimal_read'], maps: ['all', 'read', 'minimal_all', 'minimal_read'], @@ -165,6 +166,7 @@ export default function ({ getService }: FtrProviderContext) { filesManagement: ['all', 'read', 'minimal_all', 'minimal_read'], filesSharedImage: ['all', 'read', 'minimal_all', 'minimal_read'], savedObjectsManagement: ['all', 'read', 'minimal_all', 'minimal_read'], + savedQueryManagement: ['all', 'minimal_all'], osquery: [ 'all', 'read', diff --git a/x-pack/test/cloud_integration/plugins/saml_provider/metadata.xml b/x-pack/test/cloud_integration/plugins/saml_provider/metadata.xml index 8cb33193f56c9..c65972be45b45 100644 --- a/x-pack/test/cloud_integration/plugins/saml_provider/metadata.xml +++ b/x-pack/test/cloud_integration/plugins/saml_provider/metadata.xml @@ -7,24 +7,25 @@ - MIIDOTCCAiGgAwIBAgIVAN0GVNLw3IaUBuG7t6CeW8w2wyymMA0GCSqGSIb3DQEB -CwUAMDQxMjAwBgNVBAMTKUVsYXN0aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2Vu -ZXJhdGVkIENBMCAXDTIxMTAxMzEwMTU1OFoYDzIwNzExMDAxMTAxNTU4WjARMQ8w -DQYDVQQDEwZraWJhbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3 -nvfL3/26D8EkLso+t9S0m+tSJipLsBWs0dCpc8KRJ/+ijDRnAQ5lOmOAcxt43SNY -KFr0EntQEZyYaRwMIM8aPR0WYW/VV5o4fq2o/JnmHqzZJRJCwZq+5WiCiDPt012N -mRGYCMUxjlEwejue6diLAeQhZ/sfN4jUp217bMEHrhHrNBWTwwJ+Uk5TBQMhviCW -LKbsKrfluA6DGHWrXN4pH7Xmaf/Zyc9AYL/nxwv3VQHZzIAK/U/WNCgFJJ3qoFYY -6TUwDDNa30mSj165OOds9N+VmUlDC3IFiHV3osBWscSU4HJd6QJ8huHrFLLV4y4i -u62el47Qr+/8Ut3SzeIXAgMBAAGjYzBhMB0GA1UdDgQWBBQli5f2bYL9jKUA5Uxp -yRRHeCoPJzAfBgNVHSMEGDAWgBQwTCrAjlvQxik3HBocn1PDUunenjAUBgNVHREE -DTALgglsb2NhbGhvc3QwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEATFNj -WkTBPfgflGYZD4OsYvfT/rVjFKbJP/u1a0rkzNamA2QKNzI9JTOzONPTyRhe9yVS -zeO8X2rtN63l38dtgMjFQ15Xxnp7GFT7GkXfa1JR+tGSGTgVld8nLUzig+mNmBoR -nE4cNc0JJ1PsXPzfPgJ6WMp2WOoNUrQf2cm42i36Jk+7KGcosfyFMPQILZE34Geo -DAgCVpNWPgST4HYBUCHMC7S14LHLVdUXPsfGZPEqU5Zf9Hvy61rQC/RdNjnMI6JD -s57l9oHASNeEg55NQm01aOmwq/z1DXs3UP2nRmp6XCCfE61ghofO5dtV1j3cZ3f5 -dzkzSBV7H6+/MD3Y8Q== + MIIDYjCCAkqgAwIBAgIUZ2p8K7GMXGk6xwCS9S91BUl1JnAwDQYJKoZIhvcNAQEL +BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l +cmF0ZWQgQ0EwIBcNMjMwOTIzMTUyMDE0WhgPMjA3MzA5MTAxNTIwMTRaMBExDzAN +BgNVBAMTBmtpYmFuYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOU +r52dbZ5dY0BoP2p7CEnOpG+qHTNrOAqZO/OJfniPMtpGmwAMl3WZDca6u2XkV2KE +qQyevQ2ADk6G3o8S2RU8mO/+UweuCDF7LHuSdxEGTpucidZErmVhEGUOFosL5UeB +AtIDWxvWwgK+W9Yzt5IEN2HzNCZ6h0dOSk2r9EjVMG5yF4Q6kuqOYxBT7jxoaOtO +OCrgBRummtUga4T13WZ/ZIyyHpXj2+JD4YEmrDyoTa7NLaphv0hnVhHXYoYBI/c6 +2SwwAoBlmtDmlinwSACQ3o/8eLWk0tqkIP14rc3oFh3m7D2c3c2m2HXuyoSDMfGW +beG2IE1Q3idcGmeG3qsCAwEAAaOBjDCBiTAdBgNVHQ4EFgQUMOUM7w5jmIozDvnq +RpM779m5GigwHwYDVR0jBBgwFoAUMEwqwI5b0MYpNxwaHJ9Tw1Lp3p4wPAYDVR0R +BDUwM4IUaG9zdC5kb2NrZXIuaW50ZXJuYWyCCWxvY2FsaG9zdIIEZXMwM4IEZXMw +MoIEZXMwMTAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCxqvQYXSKqgpdl +SP4gXgwipAnYsoW9qkgWQODTvSBEzUdOWme0d3j7i2l6Ur/nVSv5YjkqAv1hf/yJ +Hrk9h+j29ZO/aQ/KDh5i/gTEUnPw3Bxbw47dfn23tjMWO7NCU1fr5HNztRsa/gQr +e9s07g25u/gTfTi9Fyu0lcRe3bXOLS/mFVcuC5oxuS65R9OlbIsiORkZ2EfwuNUf +wAAYOGPIjM2VlQCvBitefsd/SzRKHdxSPy6KSjkO6MGEGo87fr7B7Nx1qp1DVrK7 +q9XeP1Cuygjg9WTcnsvWvNw8CssyuFM6X/3tGjpPasXwLvNUoG2AairK2AYTWhvS +foE31cFg diff --git a/x-pack/test/functional/apps/dashboard/group1/feature_controls/dashboard_security.ts b/x-pack/test/functional/apps/dashboard/group1/feature_controls/dashboard_security.ts index 5deaac7e3a579..584822a31161b 100644 --- a/x-pack/test/functional/apps/dashboard/group1/feature_controls/dashboard_security.ts +++ b/x-pack/test/functional/apps/dashboard/group1/feature_controls/dashboard_security.ts @@ -33,6 +33,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { shouldLoginIfPrompted: false, }; + // more tests are in x-pack/test/functional/apps/saved_query_management/feature_controls/security.ts + describe('dashboard feature controls security', () => { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); diff --git a/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts b/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts index 5657f9c5da267..ee810f7ddebfb 100644 --- a/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts +++ b/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts @@ -7,8 +7,11 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; +import { getSavedQuerySecurityUtils } from '../../saved_query_management/utils/saved_query_security'; -export default function ({ getPageObjects, getService }: FtrProviderContext) { +export default function (ctx: FtrProviderContext) { + const { getPageObjects, getService } = ctx; + const savedQuerySecurityUtils = getSavedQuerySecurityUtils(ctx); const esArchiver = getService('esArchiver'); const esSupertest = getService('esSupertest'); const dataGrid = getService('dataGrid'); @@ -31,8 +34,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ]); const testSubjects = getService('testSubjects'); const appsMenu = getService('appsMenu'); - const queryBar = getService('queryBar'); - const savedQueryManagementComponent = getService('savedQueryManagementComponent'); const kibanaServer = getService('kibanaServer'); const logstashIndexName = 'logstash-2015.09.22'; @@ -40,6 +41,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRange(); } + // more tests are in x-pack/test/functional/apps/saved_query_management/feature_controls/security.ts + describe('discover feature controls security', () => { before(async () => { await kibanaServer.importExport.load( @@ -129,53 +132,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.share.clickShareTopNavButton(); }); - it('allows saving via the saved query management component popover with no saved query loaded', async () => { - await queryBar.setQuery('response:200'); - await savedQueryManagementComponent.saveNewQuery('foo', 'bar', true, false); - await savedQueryManagementComponent.savedQueryExistOrFail('foo'); - await savedQueryManagementComponent.closeSavedQueryManagementComponent(); - - await savedQueryManagementComponent.deleteSavedQuery('foo'); - await savedQueryManagementComponent.savedQueryMissingOrFail('foo'); - }); - - it('allow saving changes to a currently loaded query via the saved query management component', async () => { - await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); - await queryBar.setQuery('response:404'); - await savedQueryManagementComponent.updateCurrentlyLoadedQuery( - 'new description', - true, - false - ); - await savedQueryManagementComponent.clearCurrentlyLoadedQuery(); - await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); - const queryString = await queryBar.getQueryString(); - expect(queryString).to.eql('response:404'); - - // Reset after changing - await queryBar.setQuery('response:200'); - await savedQueryManagementComponent.updateCurrentlyLoadedQuery( - 'Ok responses for jpg files', - true, - false - ); - }); - - it('allow saving currently loaded query as a copy', async () => { - await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); - await queryBar.setQuery('response:404'); - await savedQueryManagementComponent.saveCurrentlyLoadedAsNewQuery( - 'ok2', - 'description', - true, - false - ); - await PageObjects.header.waitUntilLoadingHasFinished(); - await savedQueryManagementComponent.savedQueryExistOrFail('ok2'); - await savedQueryManagementComponent.closeSavedQueryManagementComponent(); - await testSubjects.click('showQueryBarMenu'); - await savedQueryManagementComponent.deleteSavedQuery('ok2'); - }); + savedQuerySecurityUtils.shouldAllowSavingQueries(); }); describe('global discover read-only privileges', () => { @@ -245,33 +202,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.share.clickShareTopNavButton(); }); - it('allows loading a saved query via the saved query management component', async () => { - await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); - const queryString = await queryBar.getQueryString(); - expect(queryString).to.eql('response:200'); - }); - - it('does not allow saving via the saved query management component popover with no query loaded', async () => { - await savedQueryManagementComponent.saveNewQueryMissingOrFail(); - }); - - it('does not allow saving changes to saved query from the saved query management component', async () => { - await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); - await queryBar.setQuery('response:404'); - await savedQueryManagementComponent.updateCurrentlyLoadedQueryMissingOrFail(); - }); - - it('does not allow deleting a saved query from the saved query management component', async () => { - await savedQueryManagementComponent.deleteSavedQueryMissingOrFail('OKJpgs'); - }); - - it('allows clearing the currently loaded saved query', async () => { - await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); - await savedQueryManagementComponent.clearCurrentlyLoadedQuery(); - }); + savedQuerySecurityUtils.shouldDisallowSavingButAllowLoadingSavedQueries(); }); - describe('global discover read-only privileges with url_create', () => { + describe('discover read-only privileges with url_create', () => { before(async () => { await security.role.create('global_discover_read_url_create_role', { elasticsearch: { @@ -338,30 +272,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.share.clickShareTopNavButton(); }); - it('allows loading a saved query via the saved query management component', async () => { - await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); - const queryString = await queryBar.getQueryString(); - expect(queryString).to.eql('response:200'); - }); - - it('does not allow saving via the saved query management component popover with no query loaded', async () => { - await savedQueryManagementComponent.saveNewQueryMissingOrFail(); - }); - - it('does not allow saving changes to saved query from the saved query management component', async () => { - await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); - await queryBar.setQuery('response:404'); - await savedQueryManagementComponent.updateCurrentlyLoadedQueryMissingOrFail(); - }); - - it('does not allow deleting a saved query from the saved query management component', async () => { - await savedQueryManagementComponent.deleteSavedQueryMissingOrFail('OKJpgs'); - }); - - it('allows clearing the currently loaded saved query', async () => { - await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); - await savedQueryManagementComponent.clearCurrentlyLoadedQuery(); - }); + savedQuerySecurityUtils.shouldDisallowSavingButAllowLoadingSavedQueries(); }); describe('discover and visualize privileges', () => { diff --git a/x-pack/test/functional/apps/lens/group6/annotations.ts b/x-pack/test/functional/apps/lens/group6/annotations.ts index cac637ca64ff6..cd9986b29ab03 100644 --- a/x-pack/test/functional/apps/lens/group6/annotations.ts +++ b/x-pack/test/functional/apps/lens/group6/annotations.ts @@ -26,8 +26,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const from = 'Sep 19, 2015 @ 06:31:44.000'; const to = 'Sep 23, 2015 @ 18:31:44.000'; - // Failing: See https://github.com/elastic/kibana/issues/167552 - describe.skip('lens annotations tests', () => { + describe('lens annotations tests', () => { before(async () => { await PageObjects.common.setTime({ from, to }); }); @@ -148,6 +147,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }, { submit: true, + clearWithKeyboard: true, } ); diff --git a/x-pack/test/functional/apps/lens/group6/lens_tagging.ts b/x-pack/test/functional/apps/lens/group6/lens_tagging.ts index b8d9c332f64f5..1734858f83bc7 100644 --- a/x-pack/test/functional/apps/lens/group6/lens_tagging.ts +++ b/x-pack/test/functional/apps/lens/group6/lens_tagging.ts @@ -29,8 +29,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const lensTag = 'extreme-lens-tag'; const lensTitle = 'lens tag test'; - // Failing: See https://github.com/elastic/kibana/issues/167561 - describe.skip('lens tagging', () => { + describe('lens tagging', () => { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); @@ -84,6 +83,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }, { submit: true, + clearWithKeyboard: true, } ); diff --git a/x-pack/test/functional/apps/maps/group1/feature_controls/maps_security.ts b/x-pack/test/functional/apps/maps/group1/feature_controls/maps_security.ts index 94f46763acd31..91070028b2ebf 100644 --- a/x-pack/test/functional/apps/maps/group1/feature_controls/maps_security.ts +++ b/x-pack/test/functional/apps/maps/group1/feature_controls/maps_security.ts @@ -17,6 +17,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const queryBar = getService('queryBar'); const savedQueryManagementComponent = getService('savedQueryManagementComponent'); + // more tests are in x-pack/test/functional/apps/saved_query_management/feature_controls/security.ts + describe('maps security feature controls', () => { after(async () => { // logout, so the other tests don't accidentally run as the custom users we're testing below diff --git a/x-pack/test/functional/apps/saved_query_management/config.ts b/x-pack/test/functional/apps/saved_query_management/config.ts new file mode 100644 index 0000000000000..d0d07ff200281 --- /dev/null +++ b/x-pack/test/functional/apps/saved_query_management/config.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/common/index_management/index.ts b/x-pack/test/functional/apps/saved_query_management/feature_controls/index.ts similarity index 54% rename from x-pack/test_serverless/functional/test_suites/common/index_management/index.ts rename to x-pack/test/functional/apps/saved_query_management/feature_controls/index.ts index a511d8f51280a..4c7c03dd08334 100644 --- a/x-pack/test_serverless/functional/test_suites/common/index_management/index.ts +++ b/x-pack/test/functional/apps/saved_query_management/feature_controls/index.ts @@ -7,10 +7,9 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; -export default ({ loadTestFile }: FtrProviderContext) => { - describe('Index Management', function () { - loadTestFile(require.resolve('./index_templates')); - loadTestFile(require.resolve('./indices')); - loadTestFile(require.resolve('./create_enrich_policy')); +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Feature controls', function () { + this.tags('skipFirefox'); + loadTestFile(require.resolve('./security')); }); -}; +} diff --git a/x-pack/test/functional/apps/saved_query_management/feature_controls/security.ts b/x-pack/test/functional/apps/saved_query_management/feature_controls/security.ts new file mode 100644 index 0000000000000..911b8675adf14 --- /dev/null +++ b/x-pack/test/functional/apps/saved_query_management/feature_controls/security.ts @@ -0,0 +1,191 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { getSavedQuerySecurityUtils } from '../utils/saved_query_security'; + +type AppName = 'discover' | 'dashboard' | 'maps' | 'visualize'; + +const apps: AppName[] = ['discover', 'dashboard', 'maps', 'visualize']; + +export default function (ctx: FtrProviderContext) { + const { getPageObjects, getService } = ctx; + const savedQuerySecurityUtils = getSavedQuerySecurityUtils(ctx); + const esArchiver = getService('esArchiver'); + const security = getService('security'); + const globalNav = getService('globalNav'); + const PageObjects = getPageObjects([ + 'common', + 'discover', + 'security', + 'dashboard', + 'maps', + 'visualize', + ]); + const kibanaServer = getService('kibanaServer'); + + async function login( + appName: AppName, + appPrivilege: 'read' | 'all', + globalPrivilege: 'none' | 'all' + ) { + const name = `global_saved_query_${appName}`; + const password = `password_${name}_${appPrivilege}_${globalPrivilege}`; + + await security.role.create(name, { + elasticsearch: { + indices: [{ names: ['logstash-*'], privileges: ['read', 'view_index_metadata'] }], + }, + kibana: [ + { + feature: { + [appName]: [appPrivilege], + savedQueryManagement: [globalPrivilege], + }, + spaces: ['*'], + }, + ], + }); + + await security.user.create(`${name}-user`, { + password, + roles: [name], + full_name: 'test user', + }); + + await PageObjects.security.login(`${name}-user`, password, { + expectSpaceSelector: false, + }); + } + + async function logout(appName: AppName) { + const name = `global_saved_query_${appName}`; + await PageObjects.security.forceLogout(); + await security.role.delete(name); + await security.user.delete(`${name}-user`); + } + + async function navigateToApp(appName: AppName) { + switch (appName) { + case 'discover': + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.selectIndexPattern('logstash-*'); + break; + case 'dashboard': + await PageObjects.dashboard.navigateToApp(); + await PageObjects.dashboard.gotoDashboardEditMode('A Dashboard'); + break; + case 'maps': + await PageObjects.maps.openNewMap(); + break; + case 'visualize': + await PageObjects.visualize.navigateToNewVisualization(); + await PageObjects.visualize.clickVisType('lens'); + break; + default: + break; + } + } + + describe('Security: App vs Global privilege', () => { + apps.forEach((appName) => { + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/dashboard/feature_controls/security/security.json' + ); + + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); + + // ensure we're logged out, so we can log in as the appropriate users + await PageObjects.security.forceLogout(); + }); + + after(async () => { + // logout, so the other tests don't accidentally run as the custom users we're testing below + // NOTE: Logout needs to happen before anything else to avoid flaky behavior + await PageObjects.security.forceLogout(); + + await kibanaServer.importExport.unload( + 'x-pack/test/functional/fixtures/kbn_archiver/dashboard/feature_controls/security/security.json' + ); + + await kibanaServer.savedObjects.cleanStandardList(); + }); + + describe(`${appName} read-only privileges with enabled savedQueryManagement.saveQuery privilege`, () => { + before(async () => { + await login(appName, 'read', 'all'); + await navigateToApp(appName); + await PageObjects.common.waitForTopNavToBeVisible(); + }); + + after(async () => { + await logout(appName); + }); + + it('shows read-only badge', async () => { + await globalNav.badgeExistsOrFail('Read only'); + }); + + savedQuerySecurityUtils.shouldAllowSavingQueries(); + }); + + describe(`${appName} read-only privileges with disabled savedQueryManagement.saveQuery privilege`, () => { + before(async () => { + await login(appName, 'read', 'none'); + await navigateToApp(appName); + }); + + after(async () => { + await logout(appName); + }); + + it('shows read-only badge', async () => { + await globalNav.badgeExistsOrFail('Read only'); + }); + + savedQuerySecurityUtils.shouldDisallowSavingButAllowLoadingSavedQueries(); + }); + + describe(`${appName} all privileges with enabled savedQueryManagement.saveQuery privilege`, () => { + before(async () => { + await login(appName, 'all', 'all'); + await navigateToApp(appName); + }); + + after(async () => { + await logout(appName); + }); + + it("doesn't show read-only badge", async () => { + await globalNav.badgeMissingOrFail(); + }); + + savedQuerySecurityUtils.shouldAllowSavingQueries(); + }); + + describe(`${appName} all privileges with disabled savedQueryManagement.saveQuery privilege`, () => { + before(async () => { + await login(appName, 'all', 'none'); + await navigateToApp(appName); + }); + + after(async () => { + await logout(appName); + }); + + it("doesn't show read-only badge", async () => { + await globalNav.badgeMissingOrFail(); + }); + + savedQuerySecurityUtils.shouldAllowSavingQueries(); + }); + }); + }); +} diff --git a/x-pack/test/functional/apps/saved_query_management/index.ts b/x-pack/test/functional/apps/saved_query_management/index.ts new file mode 100644 index 0000000000000..fb74e8ba554c4 --- /dev/null +++ b/x-pack/test/functional/apps/saved_query_management/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Saved query management', function () { + loadTestFile(require.resolve('./feature_controls')); + }); +} diff --git a/x-pack/test/functional/apps/saved_query_management/utils/saved_query_security.ts b/x-pack/test/functional/apps/saved_query_management/utils/saved_query_security.ts new file mode 100644 index 0000000000000..dd5dccec561f2 --- /dev/null +++ b/x-pack/test/functional/apps/saved_query_management/utils/saved_query_security.ts @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export function getSavedQuerySecurityUtils({ getPageObjects, getService }: FtrProviderContext) { + const PageObjects = getPageObjects(['header']); + const testSubjects = getService('testSubjects'); + const queryBar = getService('queryBar'); + const savedQueryManagementComponent = getService('savedQueryManagementComponent'); + + return { + shouldAllowSavingQueries: () => { + { + it('allows saving via the saved query management component popover with no saved query loaded', async () => { + await queryBar.setQuery('response:200'); + await savedQueryManagementComponent.saveNewQuery('foo', 'bar', true, false); + await savedQueryManagementComponent.savedQueryExistOrFail('foo'); + await savedQueryManagementComponent.closeSavedQueryManagementComponent(); + + await savedQueryManagementComponent.deleteSavedQuery('foo'); + await savedQueryManagementComponent.savedQueryMissingOrFail('foo'); + }); + + it('allow saving changes to a currently loaded query via the saved query management component', async () => { + await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); + await queryBar.setQuery('response:404'); + await savedQueryManagementComponent.updateCurrentlyLoadedQuery( + 'new description', + true, + false + ); + await savedQueryManagementComponent.clearCurrentlyLoadedQuery(); + await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); + const queryString = await queryBar.getQueryString(); + expect(queryString).to.eql('response:404'); + + // Reset after changing + await queryBar.setQuery('response:200'); + await savedQueryManagementComponent.updateCurrentlyLoadedQuery( + 'Ok responses for jpg files', + true, + false + ); + }); + + it('allow saving currently loaded query as a copy', async () => { + await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); + await queryBar.setQuery('response:404'); + await savedQueryManagementComponent.saveCurrentlyLoadedAsNewQuery( + 'ok2', + 'description', + true, + false + ); + await PageObjects.header.waitUntilLoadingHasFinished(); + await savedQueryManagementComponent.savedQueryExistOrFail('ok2'); + await savedQueryManagementComponent.closeSavedQueryManagementComponent(); + await testSubjects.click('showQueryBarMenu'); + await savedQueryManagementComponent.deleteSavedQuery('ok2'); + }); + } + }, + shouldDisallowSavingButAllowLoadingSavedQueries: () => { + it('allows loading a saved query via the saved query management component', async () => { + await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); + const queryString = await queryBar.getQueryString(); + expect(queryString).to.eql('response:200'); + }); + + it('does not allow saving via the saved query management component popover with no query loaded', async () => { + await savedQueryManagementComponent.saveNewQueryMissingOrFail(); + }); + + it('does not allow saving changes to saved query from the saved query management component', async () => { + await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); + await queryBar.setQuery('response:404'); + await savedQueryManagementComponent.updateCurrentlyLoadedQueryMissingOrFail(); + }); + + it('does not allow deleting a saved query from the saved query management component', async () => { + await savedQueryManagementComponent.deleteSavedQueryMissingOrFail('OKJpgs'); + }); + + it('allows clearing the currently loaded saved query', async () => { + await savedQueryManagementComponent.loadSavedQuery('OKJpgs'); + await savedQueryManagementComponent.clearCurrentlyLoadedQuery(); + }); + }, + }; +} diff --git a/x-pack/test/functional/apps/visualize/feature_controls/visualize_security.ts b/x-pack/test/functional/apps/visualize/feature_controls/visualize_security.ts index 0bf6f6fad2a75..ef2af3bdf9553 100644 --- a/x-pack/test/functional/apps/visualize/feature_controls/visualize_security.ts +++ b/x-pack/test/functional/apps/visualize/feature_controls/visualize_security.ts @@ -29,6 +29,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const queryBar = getService('queryBar'); const savedQueryManagementComponent = getService('savedQueryManagementComponent'); + // more tests are in x-pack/test/functional/apps/saved_query_management/feature_controls/security.ts + describe('visualize feature controls security', () => { before(async () => { await kibanaServer.savedObjects.cleanStandardList(); diff --git a/x-pack/test/functional/page_objects/tag_management_page.ts b/x-pack/test/functional/page_objects/tag_management_page.ts index 7e8fbd8346c1d..50d1453c1fe0f 100644 --- a/x-pack/test/functional/page_objects/tag_management_page.ts +++ b/x-pack/test/functional/page_objects/tag_management_page.ts @@ -51,13 +51,23 @@ class TagModal extends FtrService { * If a field is undefined, will not set the value (use a empty string for that) * If `submit` is true, will call `clickConfirm` once the fields have been filled. */ - async fillForm(fields: FillTagFormFields, { submit = false }: { submit?: boolean } = {}) { + async fillForm( + fields: FillTagFormFields, + { + submit = false, + clearWithKeyboard = false, + }: { submit?: boolean; clearWithKeyboard?: boolean } = {} + ) { if (fields.name !== undefined) { await this.testSubjects.click('createModalField-name'); - await this.testSubjects.setValue('createModalField-name', fields.name); + await this.testSubjects.setValue('createModalField-name', fields.name, { + clearWithKeyboard, + }); } if (fields.color !== undefined) { - await this.testSubjects.setValue('~createModalField-color', fields.color); + await this.testSubjects.setValue('~createModalField-color', fields.color, { + clearWithKeyboard, + }); // Close the popover before moving to the next input, as it can get in the way of interacting with other elements await this.testSubjects.existOrFail('euiSaturation'); await this.retry.try(async () => { @@ -69,7 +79,9 @@ class TagModal extends FtrService { } if (fields.description !== undefined) { await this.testSubjects.click('createModalField-description'); - await this.testSubjects.setValue('createModalField-description', fields.description); + await this.testSubjects.setValue('createModalField-description', fields.description, { + clearWithKeyboard, + }); } if (submit) { diff --git a/x-pack/test/osquery_cypress/agent.ts b/x-pack/test/osquery_cypress/agent.ts index 07ee5e79d9635..7456e73b2333a 100644 --- a/x-pack/test/osquery_cypress/agent.ts +++ b/x-pack/test/osquery_cypress/agent.ts @@ -32,6 +32,8 @@ export class AgentManager extends Manager { const dockerArgs = [ 'run', + '--net', + 'elastic', '--detach', '--add-host', 'host.docker.internal:host-gateway', diff --git a/x-pack/test/osquery_cypress/artifact_manager.ts b/x-pack/test/osquery_cypress/artifact_manager.ts index 0239174434a37..54b9a70d37aff 100644 --- a/x-pack/test/osquery_cypress/artifact_manager.ts +++ b/x-pack/test/osquery_cypress/artifact_manager.ts @@ -6,5 +6,5 @@ */ export async function getLatestVersion(): Promise { - return '8.10.0-SNAPSHOT'; + return '8.11.0-SNAPSHOT'; } diff --git a/x-pack/test/osquery_cypress/runner.ts b/x-pack/test/osquery_cypress/runner.ts index 08162b4670350..fddd90a336d05 100644 --- a/x-pack/test/osquery_cypress/runner.ts +++ b/x-pack/test/osquery_cypress/runner.ts @@ -7,6 +7,7 @@ import Url from 'url'; +import { verifyDockerInstalled, maybeCreateDockerNetwork } from '@kbn/es'; import { startRuntimeServices } from '@kbn/security-solution-plugin/scripts/endpoint/endpoint_agent_runner/runtime'; import { FtrProviderContext } from './ftr_provider_context'; @@ -29,6 +30,9 @@ async function setupFleetAgent({ getService }: FtrProviderContext) { const username = config.get('servers.elasticsearch.username'); const password = config.get('servers.elasticsearch.password'); + await verifyDockerInstalled(log); + await maybeCreateDockerNetwork(log); + await startRuntimeServices({ log, elasticUrl, diff --git a/x-pack/test/osquery_cypress/serverless_cli_config.ts b/x-pack/test/osquery_cypress/serverless_cli_config.ts index 8b9f15ded02c6..723a65dda94ca 100644 --- a/x-pack/test/osquery_cypress/serverless_cli_config.ts +++ b/x-pack/test/osquery_cypress/serverless_cli_config.ts @@ -7,6 +7,7 @@ import { FtrConfigProviderContext } from '@kbn/test'; +import { SERVERLESS_NODES } from '@kbn/es'; import { startOsqueryCypress } from './runner'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { @@ -32,12 +33,11 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { serverArgs: [ ...securitySolutionCypressConfig.get('kbnTestServer.serverArgs'), `--xpack.fleet.agents.fleet_server.hosts=["https://host.docker.internal:8220"]`, - `--xpack.fleet.agents.elasticsearch.host=http://host.docker.internal:${securitySolutionCypressConfig.get( - 'servers.elasticsearch.port' - )}`, + `--xpack.fleet.agents.elasticsearch.host=http://${ + SERVERLESS_NODES[0].name + }:${securitySolutionCypressConfig.get('servers.elasticsearch.port')}`, `--xpack.fleet.packages.0.name=osquery_manager`, `--xpack.fleet.packages.0.version=latest`, - `--xpack.fleet.internal.fleetServerStandalone=false`, ], }, diff --git a/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata.xml b/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata.xml index 207148665c293..cf88307879a02 100644 --- a/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata.xml +++ b/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata.xml @@ -7,24 +7,25 @@ - MIIDOTCCAiGgAwIBAgIVAN0GVNLw3IaUBuG7t6CeW8w2wyymMA0GCSqGSIb3DQEB -CwUAMDQxMjAwBgNVBAMTKUVsYXN0aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2Vu -ZXJhdGVkIENBMCAXDTIxMTAxMzEwMTU1OFoYDzIwNzExMDAxMTAxNTU4WjARMQ8w -DQYDVQQDEwZraWJhbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3 -nvfL3/26D8EkLso+t9S0m+tSJipLsBWs0dCpc8KRJ/+ijDRnAQ5lOmOAcxt43SNY -KFr0EntQEZyYaRwMIM8aPR0WYW/VV5o4fq2o/JnmHqzZJRJCwZq+5WiCiDPt012N -mRGYCMUxjlEwejue6diLAeQhZ/sfN4jUp217bMEHrhHrNBWTwwJ+Uk5TBQMhviCW -LKbsKrfluA6DGHWrXN4pH7Xmaf/Zyc9AYL/nxwv3VQHZzIAK/U/WNCgFJJ3qoFYY -6TUwDDNa30mSj165OOds9N+VmUlDC3IFiHV3osBWscSU4HJd6QJ8huHrFLLV4y4i -u62el47Qr+/8Ut3SzeIXAgMBAAGjYzBhMB0GA1UdDgQWBBQli5f2bYL9jKUA5Uxp -yRRHeCoPJzAfBgNVHSMEGDAWgBQwTCrAjlvQxik3HBocn1PDUunenjAUBgNVHREE -DTALgglsb2NhbGhvc3QwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEATFNj -WkTBPfgflGYZD4OsYvfT/rVjFKbJP/u1a0rkzNamA2QKNzI9JTOzONPTyRhe9yVS -zeO8X2rtN63l38dtgMjFQ15Xxnp7GFT7GkXfa1JR+tGSGTgVld8nLUzig+mNmBoR -nE4cNc0JJ1PsXPzfPgJ6WMp2WOoNUrQf2cm42i36Jk+7KGcosfyFMPQILZE34Geo -DAgCVpNWPgST4HYBUCHMC7S14LHLVdUXPsfGZPEqU5Zf9Hvy61rQC/RdNjnMI6JD -s57l9oHASNeEg55NQm01aOmwq/z1DXs3UP2nRmp6XCCfE61ghofO5dtV1j3cZ3f5 -dzkzSBV7H6+/MD3Y8Q== + MIIDYjCCAkqgAwIBAgIUZ2p8K7GMXGk6xwCS9S91BUl1JnAwDQYJKoZIhvcNAQEL +BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l +cmF0ZWQgQ0EwIBcNMjMwOTIzMTUyMDE0WhgPMjA3MzA5MTAxNTIwMTRaMBExDzAN +BgNVBAMTBmtpYmFuYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOU +r52dbZ5dY0BoP2p7CEnOpG+qHTNrOAqZO/OJfniPMtpGmwAMl3WZDca6u2XkV2KE +qQyevQ2ADk6G3o8S2RU8mO/+UweuCDF7LHuSdxEGTpucidZErmVhEGUOFosL5UeB +AtIDWxvWwgK+W9Yzt5IEN2HzNCZ6h0dOSk2r9EjVMG5yF4Q6kuqOYxBT7jxoaOtO +OCrgBRummtUga4T13WZ/ZIyyHpXj2+JD4YEmrDyoTa7NLaphv0hnVhHXYoYBI/c6 +2SwwAoBlmtDmlinwSACQ3o/8eLWk0tqkIP14rc3oFh3m7D2c3c2m2HXuyoSDMfGW +beG2IE1Q3idcGmeG3qsCAwEAAaOBjDCBiTAdBgNVHQ4EFgQUMOUM7w5jmIozDvnq +RpM779m5GigwHwYDVR0jBBgwFoAUMEwqwI5b0MYpNxwaHJ9Tw1Lp3p4wPAYDVR0R +BDUwM4IUaG9zdC5kb2NrZXIuaW50ZXJuYWyCCWxvY2FsaG9zdIIEZXMwM4IEZXMw +MoIEZXMwMTAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCxqvQYXSKqgpdl +SP4gXgwipAnYsoW9qkgWQODTvSBEzUdOWme0d3j7i2l6Ur/nVSv5YjkqAv1hf/yJ +Hrk9h+j29ZO/aQ/KDh5i/gTEUnPw3Bxbw47dfn23tjMWO7NCU1fr5HNztRsa/gQr +e9s07g25u/gTfTi9Fyu0lcRe3bXOLS/mFVcuC5oxuS65R9OlbIsiORkZ2EfwuNUf +wAAYOGPIjM2VlQCvBitefsd/SzRKHdxSPy6KSjkO6MGEGo87fr7B7Nx1qp1DVrK7 +q9XeP1Cuygjg9WTcnsvWvNw8CssyuFM6X/3tGjpPasXwLvNUoG2AairK2AYTWhvS +foE31cFg diff --git a/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata_2.xml b/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata_2.xml index ff1f6eccaf6d9..5e737746e8c1d 100644 --- a/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata_2.xml +++ b/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata_2.xml @@ -7,24 +7,25 @@ - MIIDOTCCAiGgAwIBAgIVAN0GVNLw3IaUBuG7t6CeW8w2wyymMA0GCSqGSIb3DQEB -CwUAMDQxMjAwBgNVBAMTKUVsYXN0aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2Vu -ZXJhdGVkIENBMCAXDTIxMTAxMzEwMTU1OFoYDzIwNzExMDAxMTAxNTU4WjARMQ8w -DQYDVQQDEwZraWJhbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3 -nvfL3/26D8EkLso+t9S0m+tSJipLsBWs0dCpc8KRJ/+ijDRnAQ5lOmOAcxt43SNY -KFr0EntQEZyYaRwMIM8aPR0WYW/VV5o4fq2o/JnmHqzZJRJCwZq+5WiCiDPt012N -mRGYCMUxjlEwejue6diLAeQhZ/sfN4jUp217bMEHrhHrNBWTwwJ+Uk5TBQMhviCW -LKbsKrfluA6DGHWrXN4pH7Xmaf/Zyc9AYL/nxwv3VQHZzIAK/U/WNCgFJJ3qoFYY -6TUwDDNa30mSj165OOds9N+VmUlDC3IFiHV3osBWscSU4HJd6QJ8huHrFLLV4y4i -u62el47Qr+/8Ut3SzeIXAgMBAAGjYzBhMB0GA1UdDgQWBBQli5f2bYL9jKUA5Uxp -yRRHeCoPJzAfBgNVHSMEGDAWgBQwTCrAjlvQxik3HBocn1PDUunenjAUBgNVHREE -DTALgglsb2NhbGhvc3QwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEATFNj -WkTBPfgflGYZD4OsYvfT/rVjFKbJP/u1a0rkzNamA2QKNzI9JTOzONPTyRhe9yVS -zeO8X2rtN63l38dtgMjFQ15Xxnp7GFT7GkXfa1JR+tGSGTgVld8nLUzig+mNmBoR -nE4cNc0JJ1PsXPzfPgJ6WMp2WOoNUrQf2cm42i36Jk+7KGcosfyFMPQILZE34Geo -DAgCVpNWPgST4HYBUCHMC7S14LHLVdUXPsfGZPEqU5Zf9Hvy61rQC/RdNjnMI6JD -s57l9oHASNeEg55NQm01aOmwq/z1DXs3UP2nRmp6XCCfE61ghofO5dtV1j3cZ3f5 -dzkzSBV7H6+/MD3Y8Q== + MIIDYjCCAkqgAwIBAgIUZ2p8K7GMXGk6xwCS9S91BUl1JnAwDQYJKoZIhvcNAQEL +BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l +cmF0ZWQgQ0EwIBcNMjMwOTIzMTUyMDE0WhgPMjA3MzA5MTAxNTIwMTRaMBExDzAN +BgNVBAMTBmtpYmFuYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOU +r52dbZ5dY0BoP2p7CEnOpG+qHTNrOAqZO/OJfniPMtpGmwAMl3WZDca6u2XkV2KE +qQyevQ2ADk6G3o8S2RU8mO/+UweuCDF7LHuSdxEGTpucidZErmVhEGUOFosL5UeB +AtIDWxvWwgK+W9Yzt5IEN2HzNCZ6h0dOSk2r9EjVMG5yF4Q6kuqOYxBT7jxoaOtO +OCrgBRummtUga4T13WZ/ZIyyHpXj2+JD4YEmrDyoTa7NLaphv0hnVhHXYoYBI/c6 +2SwwAoBlmtDmlinwSACQ3o/8eLWk0tqkIP14rc3oFh3m7D2c3c2m2HXuyoSDMfGW +beG2IE1Q3idcGmeG3qsCAwEAAaOBjDCBiTAdBgNVHQ4EFgQUMOUM7w5jmIozDvnq +RpM779m5GigwHwYDVR0jBBgwFoAUMEwqwI5b0MYpNxwaHJ9Tw1Lp3p4wPAYDVR0R +BDUwM4IUaG9zdC5kb2NrZXIuaW50ZXJuYWyCCWxvY2FsaG9zdIIEZXMwM4IEZXMw +MoIEZXMwMTAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCxqvQYXSKqgpdl +SP4gXgwipAnYsoW9qkgWQODTvSBEzUdOWme0d3j7i2l6Ur/nVSv5YjkqAv1hf/yJ +Hrk9h+j29ZO/aQ/KDh5i/gTEUnPw3Bxbw47dfn23tjMWO7NCU1fr5HNztRsa/gQr +e9s07g25u/gTfTi9Fyu0lcRe3bXOLS/mFVcuC5oxuS65R9OlbIsiORkZ2EfwuNUf +wAAYOGPIjM2VlQCvBitefsd/SzRKHdxSPy6KSjkO6MGEGo87fr7B7Nx1qp1DVrK7 +q9XeP1Cuygjg9WTcnsvWvNw8CssyuFM6X/3tGjpPasXwLvNUoG2AairK2AYTWhvS +foE31cFg diff --git a/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata_never_login.xml b/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata_never_login.xml index 6ab5e1aeb708a..a2fff3f0a4129 100644 --- a/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata_never_login.xml +++ b/x-pack/test/security_api_integration/packages/helpers/saml/idp_metadata_never_login.xml @@ -7,24 +7,25 @@ - MIIDOTCCAiGgAwIBAgIVAN0GVNLw3IaUBuG7t6CeW8w2wyymMA0GCSqGSIb3DQEB -CwUAMDQxMjAwBgNVBAMTKUVsYXN0aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2Vu -ZXJhdGVkIENBMCAXDTIxMTAxMzEwMTU1OFoYDzIwNzExMDAxMTAxNTU4WjARMQ8w -DQYDVQQDEwZraWJhbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3 -nvfL3/26D8EkLso+t9S0m+tSJipLsBWs0dCpc8KRJ/+ijDRnAQ5lOmOAcxt43SNY -KFr0EntQEZyYaRwMIM8aPR0WYW/VV5o4fq2o/JnmHqzZJRJCwZq+5WiCiDPt012N -mRGYCMUxjlEwejue6diLAeQhZ/sfN4jUp217bMEHrhHrNBWTwwJ+Uk5TBQMhviCW -LKbsKrfluA6DGHWrXN4pH7Xmaf/Zyc9AYL/nxwv3VQHZzIAK/U/WNCgFJJ3qoFYY -6TUwDDNa30mSj165OOds9N+VmUlDC3IFiHV3osBWscSU4HJd6QJ8huHrFLLV4y4i -u62el47Qr+/8Ut3SzeIXAgMBAAGjYzBhMB0GA1UdDgQWBBQli5f2bYL9jKUA5Uxp -yRRHeCoPJzAfBgNVHSMEGDAWgBQwTCrAjlvQxik3HBocn1PDUunenjAUBgNVHREE -DTALgglsb2NhbGhvc3QwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEATFNj -WkTBPfgflGYZD4OsYvfT/rVjFKbJP/u1a0rkzNamA2QKNzI9JTOzONPTyRhe9yVS -zeO8X2rtN63l38dtgMjFQ15Xxnp7GFT7GkXfa1JR+tGSGTgVld8nLUzig+mNmBoR -nE4cNc0JJ1PsXPzfPgJ6WMp2WOoNUrQf2cm42i36Jk+7KGcosfyFMPQILZE34Geo -DAgCVpNWPgST4HYBUCHMC7S14LHLVdUXPsfGZPEqU5Zf9Hvy61rQC/RdNjnMI6JD -s57l9oHASNeEg55NQm01aOmwq/z1DXs3UP2nRmp6XCCfE61ghofO5dtV1j3cZ3f5 -dzkzSBV7H6+/MD3Y8Q== + MIIDYjCCAkqgAwIBAgIUZ2p8K7GMXGk6xwCS9S91BUl1JnAwDQYJKoZIhvcNAQEL +BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l +cmF0ZWQgQ0EwIBcNMjMwOTIzMTUyMDE0WhgPMjA3MzA5MTAxNTIwMTRaMBExDzAN +BgNVBAMTBmtpYmFuYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOU +r52dbZ5dY0BoP2p7CEnOpG+qHTNrOAqZO/OJfniPMtpGmwAMl3WZDca6u2XkV2KE +qQyevQ2ADk6G3o8S2RU8mO/+UweuCDF7LHuSdxEGTpucidZErmVhEGUOFosL5UeB +AtIDWxvWwgK+W9Yzt5IEN2HzNCZ6h0dOSk2r9EjVMG5yF4Q6kuqOYxBT7jxoaOtO +OCrgBRummtUga4T13WZ/ZIyyHpXj2+JD4YEmrDyoTa7NLaphv0hnVhHXYoYBI/c6 +2SwwAoBlmtDmlinwSACQ3o/8eLWk0tqkIP14rc3oFh3m7D2c3c2m2HXuyoSDMfGW +beG2IE1Q3idcGmeG3qsCAwEAAaOBjDCBiTAdBgNVHQ4EFgQUMOUM7w5jmIozDvnq +RpM779m5GigwHwYDVR0jBBgwFoAUMEwqwI5b0MYpNxwaHJ9Tw1Lp3p4wPAYDVR0R +BDUwM4IUaG9zdC5kb2NrZXIuaW50ZXJuYWyCCWxvY2FsaG9zdIIEZXMwM4IEZXMw +MoIEZXMwMTAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCxqvQYXSKqgpdl +SP4gXgwipAnYsoW9qkgWQODTvSBEzUdOWme0d3j7i2l6Ur/nVSv5YjkqAv1hf/yJ +Hrk9h+j29ZO/aQ/KDh5i/gTEUnPw3Bxbw47dfn23tjMWO7NCU1fr5HNztRsa/gQr +e9s07g25u/gTfTi9Fyu0lcRe3bXOLS/mFVcuC5oxuS65R9OlbIsiORkZ2EfwuNUf +wAAYOGPIjM2VlQCvBitefsd/SzRKHdxSPy6KSjkO6MGEGo87fr7B7Nx1qp1DVrK7 +q9XeP1Cuygjg9WTcnsvWvNw8CssyuFM6X/3tGjpPasXwLvNUoG2AairK2AYTWhvS +foE31cFg diff --git a/x-pack/test/security_api_integration/plugins/saml_provider/metadata.xml b/x-pack/test/security_api_integration/plugins/saml_provider/metadata.xml index 8cb33193f56c9..c65972be45b45 100644 --- a/x-pack/test/security_api_integration/plugins/saml_provider/metadata.xml +++ b/x-pack/test/security_api_integration/plugins/saml_provider/metadata.xml @@ -7,24 +7,25 @@ - MIIDOTCCAiGgAwIBAgIVAN0GVNLw3IaUBuG7t6CeW8w2wyymMA0GCSqGSIb3DQEB -CwUAMDQxMjAwBgNVBAMTKUVsYXN0aWMgQ2VydGlmaWNhdGUgVG9vbCBBdXRvZ2Vu -ZXJhdGVkIENBMCAXDTIxMTAxMzEwMTU1OFoYDzIwNzExMDAxMTAxNTU4WjARMQ8w -DQYDVQQDEwZraWJhbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3 -nvfL3/26D8EkLso+t9S0m+tSJipLsBWs0dCpc8KRJ/+ijDRnAQ5lOmOAcxt43SNY -KFr0EntQEZyYaRwMIM8aPR0WYW/VV5o4fq2o/JnmHqzZJRJCwZq+5WiCiDPt012N -mRGYCMUxjlEwejue6diLAeQhZ/sfN4jUp217bMEHrhHrNBWTwwJ+Uk5TBQMhviCW -LKbsKrfluA6DGHWrXN4pH7Xmaf/Zyc9AYL/nxwv3VQHZzIAK/U/WNCgFJJ3qoFYY -6TUwDDNa30mSj165OOds9N+VmUlDC3IFiHV3osBWscSU4HJd6QJ8huHrFLLV4y4i -u62el47Qr+/8Ut3SzeIXAgMBAAGjYzBhMB0GA1UdDgQWBBQli5f2bYL9jKUA5Uxp -yRRHeCoPJzAfBgNVHSMEGDAWgBQwTCrAjlvQxik3HBocn1PDUunenjAUBgNVHREE -DTALgglsb2NhbGhvc3QwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEATFNj -WkTBPfgflGYZD4OsYvfT/rVjFKbJP/u1a0rkzNamA2QKNzI9JTOzONPTyRhe9yVS -zeO8X2rtN63l38dtgMjFQ15Xxnp7GFT7GkXfa1JR+tGSGTgVld8nLUzig+mNmBoR -nE4cNc0JJ1PsXPzfPgJ6WMp2WOoNUrQf2cm42i36Jk+7KGcosfyFMPQILZE34Geo -DAgCVpNWPgST4HYBUCHMC7S14LHLVdUXPsfGZPEqU5Zf9Hvy61rQC/RdNjnMI6JD -s57l9oHASNeEg55NQm01aOmwq/z1DXs3UP2nRmp6XCCfE61ghofO5dtV1j3cZ3f5 -dzkzSBV7H6+/MD3Y8Q== + MIIDYjCCAkqgAwIBAgIUZ2p8K7GMXGk6xwCS9S91BUl1JnAwDQYJKoZIhvcNAQEL +BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l +cmF0ZWQgQ0EwIBcNMjMwOTIzMTUyMDE0WhgPMjA3MzA5MTAxNTIwMTRaMBExDzAN +BgNVBAMTBmtpYmFuYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOU +r52dbZ5dY0BoP2p7CEnOpG+qHTNrOAqZO/OJfniPMtpGmwAMl3WZDca6u2XkV2KE +qQyevQ2ADk6G3o8S2RU8mO/+UweuCDF7LHuSdxEGTpucidZErmVhEGUOFosL5UeB +AtIDWxvWwgK+W9Yzt5IEN2HzNCZ6h0dOSk2r9EjVMG5yF4Q6kuqOYxBT7jxoaOtO +OCrgBRummtUga4T13WZ/ZIyyHpXj2+JD4YEmrDyoTa7NLaphv0hnVhHXYoYBI/c6 +2SwwAoBlmtDmlinwSACQ3o/8eLWk0tqkIP14rc3oFh3m7D2c3c2m2HXuyoSDMfGW +beG2IE1Q3idcGmeG3qsCAwEAAaOBjDCBiTAdBgNVHQ4EFgQUMOUM7w5jmIozDvnq +RpM779m5GigwHwYDVR0jBBgwFoAUMEwqwI5b0MYpNxwaHJ9Tw1Lp3p4wPAYDVR0R +BDUwM4IUaG9zdC5kb2NrZXIuaW50ZXJuYWyCCWxvY2FsaG9zdIIEZXMwM4IEZXMw +MoIEZXMwMTAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCxqvQYXSKqgpdl +SP4gXgwipAnYsoW9qkgWQODTvSBEzUdOWme0d3j7i2l6Ur/nVSv5YjkqAv1hf/yJ +Hrk9h+j29ZO/aQ/KDh5i/gTEUnPw3Bxbw47dfn23tjMWO7NCU1fr5HNztRsa/gQr +e9s07g25u/gTfTi9Fyu0lcRe3bXOLS/mFVcuC5oxuS65R9OlbIsiORkZ2EfwuNUf +wAAYOGPIjM2VlQCvBitefsd/SzRKHdxSPy6KSjkO6MGEGo87fr7B7Nx1qp1DVrK7 +q9XeP1Cuygjg9WTcnsvWvNw8CssyuFM6X/3tGjpPasXwLvNUoG2AairK2AYTWhvS +foE31cFg diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index bf7d721fc0ba2..de73481e8473e 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -144,5 +144,6 @@ "@kbn/coloring", "@kbn/profiling-utils", "@kbn/profiling-data-access-plugin", + "@kbn/es", ] } diff --git a/x-pack/test_serverless/api_integration/config.base.ts b/x-pack/test_serverless/api_integration/config.base.ts index 4ffdbfeef108a..096ff9c79acb3 100644 --- a/x-pack/test_serverless/api_integration/config.base.ts +++ b/x-pack/test_serverless/api_integration/config.base.ts @@ -20,6 +20,13 @@ export function createTestConfig(options: CreateTestConfigOptions) { ...services, ...options.services, }, + esTestCluster: { + ...svlSharedConfig.get('esTestCluster'), + serverArgs: [ + ...svlSharedConfig.get('esTestCluster.serverArgs'), + ...(options.esServerArgs ?? []), + ], + }, kbnTestServer: { ...svlSharedConfig.get('kbnTestServer'), serverArgs: [ diff --git a/x-pack/test_serverless/api_integration/test_suites/common/README.md b/x-pack/test_serverless/api_integration/test_suites/common/README.md new file mode 100644 index 0000000000000..8f9d86bf921ef --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/README.md @@ -0,0 +1,24 @@ +# Kibana Serverless Common API Integration Tests + +The `common` tests in this directory are not project specific and are running +in two or three of the projects. You can use tags to exclude one of the +projects: `skipSvlOblt`, `skipSvlSearch`, `skipSvlSec`. If no such tag is added, +the test will run in all three projects. +Tests that are designed to only run in one of the projects should be added to +the project specific test directory and not to `common` with two skips. + +For more information about serverless tests please refer to +[x-pack/test_serverless/README](https://github.com/elastic/kibana/blob/main/x-pack/test_serverless/README.md). + +## Organizing common tests + +- Common tests don't have dedicated config files as they run as part of project +configs. +- There's no top level index file and tests are organized in sub-directories in +order to better group them based on test run time. +- **If you add a new `common` sub-directory, remember to add it to the `common_configs` of all projects (`x-pack/test_serverless/api_integration/test_suites/[observability|search|security]/common_configs`)** + + + + + diff --git a/x-pack/test_serverless/api_integration/test_suites/common/elasticsearch_api.ts b/x-pack/test_serverless/api_integration/test_suites/common/elasticsearch_api/home.ts similarity index 84% rename from x-pack/test_serverless/api_integration/test_suites/common/elasticsearch_api.ts rename to x-pack/test_serverless/api_integration/test_suites/common/elasticsearch_api/home.ts index b55f36cab29aa..1008378140d64 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/elasticsearch_api.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/elasticsearch_api/home.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const esSupertest = getService('esSupertest'); const svlCommonApi = getService('svlCommonApi'); - describe('Elasticsearch API', function () { + describe('Home', function () { it('can request /', async () => { const { body, status } = await esSupertest.get('/'); svlCommonApi.assertResponseStatusCode(200, status, body); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/elasticsearch_api/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/elasticsearch_api/index.ts new file mode 100644 index 0000000000000..0d53235d8e0b6 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/elasticsearch_api/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Elasticsearch API', () => { + loadTestFile(require.resolve('./home')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/index.ts deleted file mode 100644 index fffe386b7c2ba..0000000000000 --- a/x-pack/test_serverless/api_integration/test_suites/common/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ loadTestFile }: FtrProviderContext) { - describe('serverless common API', function () { - loadTestFile(require.resolve('./encrypted_saved_objects')); - loadTestFile(require.resolve('./security/anonymous')); - loadTestFile(require.resolve('./security/api_keys')); - loadTestFile(require.resolve('./security/authentication')); - loadTestFile(require.resolve('./security/authentication_http')); - loadTestFile(require.resolve('./security/authorization')); - loadTestFile(require.resolve('./security/misc')); - loadTestFile(require.resolve('./security/response_headers')); - loadTestFile(require.resolve('./security/role_mappings')); - loadTestFile(require.resolve('./security/sessions')); - loadTestFile(require.resolve('./security/users')); - loadTestFile(require.resolve('./security/user_profiles')); - loadTestFile(require.resolve('./security/views')); - loadTestFile(require.resolve('./spaces')); - loadTestFile(require.resolve('./rollups')); - loadTestFile(require.resolve('./scripted_fields')); - loadTestFile(require.resolve('./index_management')); - loadTestFile(require.resolve('./alerting')); - loadTestFile(require.resolve('./ingest_pipelines')); - loadTestFile(require.resolve('./data_view_field_editor')); - loadTestFile(require.resolve('./data_views')); - loadTestFile(require.resolve('./kql_telemetry')); - loadTestFile(require.resolve('./scripts_tests')); - loadTestFile(require.resolve('./search_oss')); - loadTestFile(require.resolve('./search_xpack')); - loadTestFile(require.resolve('./elasticsearch_api')); - }); -} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts new file mode 100644 index 0000000000000..9c634b7f5590f --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Management', () => { + loadTestFile(require.resolve('./ingest_pipelines')); + loadTestFile(require.resolve('./rollups')); + loadTestFile(require.resolve('./scripted_fields')); + loadTestFile(require.resolve('./spaces')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/ingest_pipelines.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/ingest_pipelines.ts similarity index 99% rename from x-pack/test_serverless/api_integration/test_suites/common/ingest_pipelines.ts rename to x-pack/test_serverless/api_integration/test_suites/common/management/ingest_pipelines.ts index 1e5ee6d39bb71..0f4866f3c3a22 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/ingest_pipelines.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/ingest_pipelines.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { IngestPutPipelineRequest } from '@elastic/elasticsearch/lib/api/types'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/rollups.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/rollups.ts similarity index 96% rename from x-pack/test_serverless/api_integration/test_suites/common/rollups.ts rename to x-pack/test_serverless/api_integration/test_suites/common/management/rollups.ts index c1ec42564e481..62baa03c10aad 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/rollups.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/rollups.ts @@ -10,7 +10,7 @@ import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { INITIAL_REST_VERSION_INTERNAL } from '@kbn/data-views-plugin/server/constants'; import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common/src/constants'; import { FIELDS_FOR_WILDCARD_PATH as BASE_URI } from '@kbn/data-views-plugin/common/constants'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/scripted_fields.ts similarity index 95% rename from x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts rename to x-pack/test_serverless/api_integration/test_suites/common/management/scripted_fields.ts index 7cc4089814c77..bfe1078df11be 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/scripted_fields.ts @@ -7,7 +7,7 @@ import expect from 'expect'; import { DATA_VIEW_PATH } from '@kbn/data-views-plugin/server'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/spaces.ts b/x-pack/test_serverless/api_integration/test_suites/common/management/spaces.ts similarity index 99% rename from x-pack/test_serverless/api_integration/test_suites/common/spaces.ts rename to x-pack/test_serverless/api_integration/test_suites/common/management/spaces.ts index 78c2456f85ca1..e20d2ef30d752 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/spaces.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/management/spaces.ts @@ -6,7 +6,7 @@ */ import expect from 'expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const svlCommonApi = getService('svlCommonApi'); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/anonymous.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/anonymous.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/anonymous.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/anonymous.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/api_keys.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/api_keys.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/api_keys.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/api_keys.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/authentication.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authentication.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/authentication.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/authentication.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/authentication_http.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authentication_http.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/authentication_http.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/authentication_http.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/authorization.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/authorization.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/encrypted_saved_objects.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts similarity index 92% rename from x-pack/test_serverless/api_integration/test_suites/common/encrypted_saved_objects.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts index be5dc924c839d..63d81773398cd 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/encrypted_saved_objects.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/encrypted_saved_objects.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const svlCommonApi = getService('svlCommonApi'); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts new file mode 100644 index 0000000000000..8297aa53bfc6b --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('serverless common API', function () { + loadTestFile(require.resolve('./anonymous')); + loadTestFile(require.resolve('./api_keys')); + loadTestFile(require.resolve('./authentication')); + loadTestFile(require.resolve('./authentication_http')); + loadTestFile(require.resolve('./authorization')); + loadTestFile(require.resolve('./encrypted_saved_objects')); + loadTestFile(require.resolve('./misc')); + loadTestFile(require.resolve('./response_headers')); + loadTestFile(require.resolve('./role_mappings')); + loadTestFile(require.resolve('./sessions')); + loadTestFile(require.resolve('./users')); + loadTestFile(require.resolve('./user_profiles')); + loadTestFile(require.resolve('./views')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/misc.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/misc.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/misc.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/misc.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/response_headers.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/response_headers.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/response_headers.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/response_headers.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/role_mappings.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/role_mappings.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/role_mappings.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/role_mappings.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/sessions.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/sessions.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/sessions.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/sessions.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/user_profiles.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/user_profiles.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/user_profiles.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/user_profiles.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/users.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/users.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/users.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/users.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/views.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/views.ts similarity index 100% rename from x-pack/test_serverless/api_integration/test_suites/common/security/views.ts rename to x-pack/test_serverless/api_integration/test_suites/common/platform_security/views.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts new file mode 100644 index 0000000000000..a04b9074662da --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/alerting'), + require.resolve('../../common/data_view_field_editor'), + require.resolve('../../common/data_views'), + require.resolve('../../common/elasticsearch_api'), + require.resolve('../../common/index_management'), + require.resolve('../../common/kql_telemetry'), + require.resolve('../../common/management'), + require.resolve('../../common/platform_security'), + require.resolve('../../common/scripts_tests'), + require.resolve('../../common/search_oss'), + require.resolve('../../common/search_xpack'), + ], + junit: { + reportName: 'Serverless Observability API Integration Tests - Common Group 1', + }, + }; +} diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts index 1e092616323f1..bedcfb3889b00 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts @@ -23,4 +23,8 @@ export default createTestConfig({ kbnServerArgs: ['--xpack.observability.unsafe.thresholdRule.enabled=true'], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml + esServerArgs: ['xpack.ml.dfa.enabled=false', 'xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/config.ts b/x-pack/test_serverless/api_integration/test_suites/observability/config.ts index 706d27cf9024a..9901c9736b9aa 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/config.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/config.ts @@ -10,10 +10,14 @@ import { services } from './apm_api_integration/common/services'; export default createTestConfig({ serverlessProject: 'oblt', - testFiles: [require.resolve('../common'), require.resolve('.')], + testFiles: [require.resolve('.')], junit: { reportName: 'Serverless Observability API Integration Tests', }, suiteTags: { exclude: ['skipSvlOblt'] }, services, + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml + esServerArgs: ['xpack.ml.dfa.enabled=false', 'xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_fired.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_fired.ts index 0389d0eace4e7..de26cb2e906d4 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_fired.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_fired.ts @@ -23,10 +23,11 @@ export default function ({ getService }: FtrProviderContext) { const dataViewApi = getService('dataViewApi'); const logger = getService('log'); - // Blocked API: index_not_found_exception: no such index [.alerts-observability.threshold.alerts-default] - // Issue: https://github.com/elastic/kibana/issues/165138 - describe.skip('Custom Threshold rule - AVG - PCT - FIRED', () => { + describe('Custom Threshold rule - AVG - PCT - FIRED', () => { const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default'; + // DATE_VIEW should match the index template: + // x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json + const DATE_VIEW = 'kbn-data-forge-fake_hosts'; const ALERT_ACTION_INDEX = 'alert-action-threshold'; const DATA_VIEW_ID = 'data-view-id'; let infraDataIndex: string; @@ -34,11 +35,15 @@ export default function ({ getService }: FtrProviderContext) { let ruleId: string; before(async () => { - infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); + infraDataIndex = await generate({ + esClient, + lookback: 'now-15m', + logger, + }); await dataViewApi.create({ - name: 'metrics-fake_hosts', + name: DATE_VIEW, id: DATA_VIEW_ID, - title: 'metrics-fake_hosts', + title: DATE_VIEW, }); }); @@ -57,7 +62,7 @@ export default function ({ getService }: FtrProviderContext) { }); await esClient.deleteByQuery({ index: '.kibana-event-log-*', - query: { term: { 'kibana.alert.rule.consumer': 'logs' } }, + query: { term: { 'kibana.alert.rule.consumer': 'apm' } }, }); await dataViewApi.delete({ id: DATA_VIEW_ID, @@ -75,7 +80,7 @@ export default function ({ getService }: FtrProviderContext) { const createdRule = await alertingApi.createRule({ tags: ['observability'], - consumer: 'logs', + consumer: 'apm', name: 'Threshold rule', ruleTypeId: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, params: { @@ -142,7 +147,7 @@ export default function ({ getService }: FtrProviderContext) { 'kibana.alert.rule.category', 'Custom threshold (BETA)' ); - expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); + expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'apm'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.producer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.revision', 0); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_no_data.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_no_data.ts index 0bd7fdf7bbb6f..b1cc5c41f6805 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_no_data.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_no_data.ts @@ -20,9 +20,7 @@ export default function ({ getService }: FtrProviderContext) { const alertingApi = getService('alertingApi'); const dataViewApi = getService('dataViewApi'); - // Blocked API: index_not_found_exception: no such index [.alerts-observability.threshold.alerts-default] - // Issue: https://github.com/elastic/kibana/issues/165138 - describe.skip('Custom Threshold rule - AVG - PCT - NoData', () => { + describe('Custom Threshold rule - AVG - PCT - NoData', () => { const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default'; const ALERT_ACTION_INDEX = 'alert-action-threshold'; const DATA_VIEW_ID = 'data-view-id-no-data'; @@ -52,7 +50,7 @@ export default function ({ getService }: FtrProviderContext) { }); await esClient.deleteByQuery({ index: '.kibana-event-log-*', - query: { term: { 'kibana.alert.rule.consumer': 'logs' } }, + query: { term: { 'kibana.alert.rule.consumer': 'apm' } }, }); await dataViewApi.delete({ id: DATA_VIEW_ID, @@ -68,7 +66,7 @@ export default function ({ getService }: FtrProviderContext) { const createdRule = await alertingApi.createRule({ tags: ['observability'], - consumer: 'logs', + consumer: 'apm', name: 'Threshold rule', ruleTypeId: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, params: { @@ -135,7 +133,7 @@ export default function ({ getService }: FtrProviderContext) { 'kibana.alert.rule.category', 'Custom threshold (BETA)' ); - expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); + expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'apm'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.producer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.revision', 0); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts index 5ee54e1c9ad17..b4b1858e9bac4 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts @@ -29,9 +29,11 @@ export default function ({ getService }: FtrProviderContext) { const alertingApi = getService('alertingApi'); const dataViewApi = getService('dataViewApi'); - // Issue: https://github.com/elastic/kibana/issues/165138 - describe.skip('Custom Threshold rule - CUSTOM_EQ - AVG - BYTES - FIRED', () => { + describe('Custom Threshold rule - CUSTOM_EQ - AVG - BYTES - FIRED', () => { const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default'; + // DATE_VIEW should match the index template: + // x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json + const DATE_VIEW = 'kbn-data-forge-fake_hosts'; const ALERT_ACTION_INDEX = 'alert-action-threshold'; const DATA_VIEW_ID = 'data-view-id'; let infraDataIndex: string; @@ -41,9 +43,9 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); await dataViewApi.create({ - name: 'metrics-fake_hosts', + name: DATE_VIEW, id: DATA_VIEW_ID, - title: 'metrics-fake_hosts', + title: DATE_VIEW, }); }); @@ -80,7 +82,7 @@ export default function ({ getService }: FtrProviderContext) { const createdRule = await alertingApi.createRule({ tags: ['observability'], - consumer: 'logs', + consumer: 'apm', name: 'Threshold rule', ruleTypeId: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, params: { @@ -149,7 +151,7 @@ export default function ({ getService }: FtrProviderContext) { 'kibana.alert.rule.category', 'Custom threshold (BETA)' ); - expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); + expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'apm'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.producer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.revision', 0); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/documents_count_fired.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/documents_count_fired.ts index 56412a8380d2c..f5b0305993a91 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/documents_count_fired.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/documents_count_fired.ts @@ -23,9 +23,11 @@ export default function ({ getService }: FtrProviderContext) { const alertingApi = getService('alertingApi'); const dataViewApi = getService('dataViewApi'); - // Issue: https://github.com/elastic/kibana/issues/165138 - describe.skip('Custom Threshold rule - DOCUMENTS_COUNT - FIRED', () => { + describe('Custom Threshold rule - DOCUMENTS_COUNT - FIRED', () => { const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default'; + // DATE_VIEW should match the index template: + // x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json + const DATE_VIEW = 'kbn-data-forge-fake_hosts'; const ALERT_ACTION_INDEX = 'alert-action-threshold'; const DATA_VIEW_ID = 'data-view-id'; let infraDataIndex: string; @@ -35,9 +37,9 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); await dataViewApi.create({ - name: 'metrics-fake_hosts', + name: DATE_VIEW, id: DATA_VIEW_ID, - title: 'metrics-fake_hosts', + title: DATE_VIEW, }); }); @@ -56,7 +58,7 @@ export default function ({ getService }: FtrProviderContext) { }); await esClient.deleteByQuery({ index: '.kibana-event-log-*', - query: { term: { 'kibana.alert.rule.consumer': 'logs' } }, + query: { term: { 'kibana.alert.rule.consumer': 'apm' } }, }); await dataViewApi.delete({ id: DATA_VIEW_ID, @@ -74,7 +76,7 @@ export default function ({ getService }: FtrProviderContext) { const createdRule = await alertingApi.createRule({ tags: ['observability'], - consumer: 'logs', + consumer: 'apm', name: 'Threshold rule', ruleTypeId: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, params: { @@ -139,7 +141,7 @@ export default function ({ getService }: FtrProviderContext) { 'kibana.alert.rule.category', 'Custom threshold (BETA)' ); - expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); + expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'apm'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.producer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.revision', 0); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/group_by_fired.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/group_by_fired.ts index f1b3c949421d4..09ae231091369 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/group_by_fired.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/group_by_fired.ts @@ -33,9 +33,11 @@ export default function ({ getService }: FtrProviderContext) { let alertId: string; let startedAt: string; - // Issue: https://github.com/elastic/kibana/issues/165138 - describe.skip('Custom Threshold rule - GROUP_BY - FIRED', () => { + describe('Custom Threshold rule - GROUP_BY - FIRED', () => { const CUSTOM_THRESHOLD_RULE_ALERT_INDEX = '.alerts-observability.threshold.alerts-default'; + // DATE_VIEW should match the index template: + // x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json + const DATE_VIEW = 'kbn-data-forge-fake_hosts'; const ALERT_ACTION_INDEX = 'alert-action-threshold'; const DATA_VIEW_ID = 'data-view-id'; let infraDataIndex: string; @@ -45,9 +47,9 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); await dataViewApi.create({ - name: 'metrics-fake_hosts', + name: DATE_VIEW, id: DATA_VIEW_ID, - title: 'metrics-fake_hosts', + title: DATE_VIEW, }); }); @@ -66,7 +68,7 @@ export default function ({ getService }: FtrProviderContext) { }); await esClient.deleteByQuery({ index: '.kibana-event-log-*', - query: { term: { 'kibana.alert.rule.consumer': 'logs' } }, + query: { term: { 'kibana.alert.rule.consumer': 'apm' } }, }); await dataViewApi.delete({ id: DATA_VIEW_ID, @@ -84,7 +86,7 @@ export default function ({ getService }: FtrProviderContext) { const createdRule = await alertingApi.createRule({ tags: ['observability'], - consumer: 'logs', + consumer: 'apm', name: 'Threshold rule', ruleTypeId: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, params: { @@ -158,7 +160,7 @@ export default function ({ getService }: FtrProviderContext) { 'kibana.alert.rule.category', 'Custom threshold (BETA)' ); - expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); + expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'apm'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.producer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.revision', 0); @@ -224,7 +226,8 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source?.ruleType).eql('observability.rules.custom_threshold'); expect(resp.hits.hits[0]._source?.alertDetailsUrl).eql( - `${protocol}://${hostname}:${port}/app/observability/alerts?_a=(kuery:%27kibana.alert.uuid:%20%22${alertId}%22%27%2CrangeFrom:%27${rangeFrom}%27%2CrangeTo:now%2Cstatus:all)` + // Added the S to protocol.getUrlParts as not returning the correct value. + `${protocol}s://${hostname}:${port}/app/observability/alerts?_a=(kuery:%27kibana.alert.uuid:%20%22${alertId}%22%27%2CrangeFrom:%27${rangeFrom}%27%2CrangeTo:now%2Cstatus:all)` ); expect(resp.hits.hits[0]._source?.reason).eql( 'Custom equation is 0.8 in the last 1 min for host-0. Alert when >= 0.2.' diff --git a/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts new file mode 100644 index 0000000000000..8a983926a12e6 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/alerting'), + require.resolve('../../common/data_view_field_editor'), + require.resolve('../../common/data_views'), + require.resolve('../../common/elasticsearch_api'), + require.resolve('../../common/index_management'), + require.resolve('../../common/kql_telemetry'), + require.resolve('../../common/management'), + require.resolve('../../common/platform_security'), + require.resolve('../../common/scripts_tests'), + require.resolve('../../common/search_oss'), + require.resolve('../../common/search_xpack'), + ], + junit: { + reportName: 'Serverless Search API Integration Tests - Common Group 1', + }, + }; +} diff --git a/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts index 9a9d0064bc5e6..d56585c4634f9 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts @@ -21,4 +21,8 @@ export default createTestConfig({ kbnServerArgs: [], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/esproject/config/elasticsearch.yml + esServerArgs: ['xpack.ml.ad.enabled=false', 'xpack.ml.dfa.enabled=false'], }); diff --git a/x-pack/test_serverless/api_integration/test_suites/search/config.ts b/x-pack/test_serverless/api_integration/test_suites/search/config.ts index fa1cefff02273..7afde0944020c 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/config.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/config.ts @@ -9,9 +9,13 @@ import { createTestConfig } from '../../config.base'; export default createTestConfig({ serverlessProject: 'es', - testFiles: [require.resolve('../common'), require.resolve('.')], + testFiles: [require.resolve('.')], junit: { reportName: 'Serverless Search API Integration Tests', }, suiteTags: { exclude: ['skipSvlSearch'] }, + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/esproject/config/elasticsearch.yml + esServerArgs: ['xpack.ml.ad.enabled=false', 'xpack.ml.dfa.enabled=false'], }); diff --git a/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts new file mode 100644 index 0000000000000..995c62fea1fd5 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/alerting'), + require.resolve('../../common/data_view_field_editor'), + require.resolve('../../common/data_views'), + require.resolve('../../common/elasticsearch_api'), + require.resolve('../../common/index_management'), + require.resolve('../../common/kql_telemetry'), + require.resolve('../../common/management'), + require.resolve('../../common/platform_security'), + require.resolve('../../common/scripts_tests'), + require.resolve('../../common/search_oss'), + require.resolve('../../common/search_xpack'), + ], + junit: { + reportName: 'Serverless Security API Integration Tests - Common Group 1', + }, + }; +} diff --git a/x-pack/test_serverless/api_integration/test_suites/security/config.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/security/config.feature_flags.ts index 20bce40a9f205..58ad1ac2105c2 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/config.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/config.feature_flags.ts @@ -21,4 +21,8 @@ export default createTestConfig({ kbnServerArgs: [], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/security/config/elasticsearch.yml + esServerArgs: ['xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/api_integration/test_suites/security/config.ts b/x-pack/test_serverless/api_integration/test_suites/security/config.ts index e313d7abdf9d6..5066518f92671 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/config.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/config.ts @@ -9,9 +9,13 @@ import { createTestConfig } from '../../config.base'; export default createTestConfig({ serverlessProject: 'security', - testFiles: [require.resolve('../common'), require.resolve('.')], + testFiles: [require.resolve('.')], junit: { reportName: 'Serverless Security API Integration Tests', }, suiteTags: { exclude: ['skipSvlSec'] }, + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/security/config/elasticsearch.yml + esServerArgs: ['xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/config.base.ts b/x-pack/test_serverless/functional/config.base.ts index a570d7a7e72f9..3db533e9d930c 100644 --- a/x-pack/test_serverless/functional/config.base.ts +++ b/x-pack/test_serverless/functional/config.base.ts @@ -22,6 +22,13 @@ export function createTestConfig(options: CreateTestConfigOptions) { pageObjects, services, + esTestCluster: { + ...svlSharedConfig.get('esTestCluster'), + serverArgs: [ + ...svlSharedConfig.get('esTestCluster.serverArgs'), + ...(options.esServerArgs ?? []), + ], + }, kbnTestServer: { ...svlSharedConfig.get('kbnTestServer'), serverArgs: [ diff --git a/x-pack/test_serverless/functional/test_suites/common/README.md b/x-pack/test_serverless/functional/test_suites/common/README.md new file mode 100644 index 0000000000000..cfb8e62032991 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/README.md @@ -0,0 +1,24 @@ +# Kibana Serverless Common Functional Tests + +The `common` tests in this directory are not project specific and are running +in two or three of the projects. You can use tags to exclude one of the +projects: `skipSvlOblt`, `skipSvlSearch`, `skipSvlSec`. If no such tag is added, +the test will run in all three projects. +Tests that are designed to only run in one of the projects should be added to +the project specific test directory and not to `common` with two skips. + +For more information about serverless tests please refer to +[x-pack/test_serverless/README](https://github.com/elastic/kibana/blob/main/x-pack/test_serverless/README.md). + +## Organizing common tests + +- Common tests don't have dedicated config files as they run as part of project +configs. +- There's no top level index file and tests are organized in sub-directories in +order to better group them based on test run time. +- **If you add a new `common` sub-directory, remember to add it to the `common_configs` of all projects (`x-pack/test_serverless/functional/test_suites/[observability|search|security]/common_configs`)** + + + + + diff --git a/x-pack/test_serverless/functional/test_suites/common/examples/index.ts b/x-pack/test_serverless/functional/test_suites/common/examples/index.ts new file mode 100644 index 0000000000000..1425c2275d69b --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/examples/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Serverless Common UI - Examples', function () { + this.tags('skipMKI'); + loadTestFile(require.resolve('./data_view_field_editor_example')); + loadTestFile(require.resolve('./discover_customization_examples')); + loadTestFile(require.resolve('./field_formats')); + loadTestFile(require.resolve('./partial_results')); + loadTestFile(require.resolve('./search')); + loadTestFile(require.resolve('./search_examples')); + loadTestFile(require.resolve('./unified_field_list_examples')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/home_page.ts b/x-pack/test_serverless/functional/test_suites/common/home_page/home_page.ts similarity index 92% rename from x-pack/test_serverless/functional/test_suites/common/home_page.ts rename to x-pack/test_serverless/functional/test_suites/common/home_page/home_page.ts index 744fc48c3ee41..d8d986daf8ed1 100644 --- a/x-pack/test_serverless/functional/test_suites/common/home_page.ts +++ b/x-pack/test_serverless/functional/test_suites/common/home_page/home_page.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObject, getService }: FtrProviderContext) { const svlCommonPage = getPageObject('svlCommonPage'); diff --git a/x-pack/test_serverless/functional/test_suites/common/home_page/index.ts b/x-pack/test_serverless/functional/test_suites/common/home_page/index.ts new file mode 100644 index 0000000000000..73cd38fc339d9 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/home_page/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Serverless Common UI - Home Page', function () { + loadTestFile(require.resolve('./home_page')); + loadTestFile(require.resolve('./sample_data')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/home_page/sample_data.ts b/x-pack/test_serverless/functional/test_suites/common/home_page/sample_data.ts new file mode 100644 index 0000000000000..803e0edeba789 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/home_page/sample_data.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getPageObjects }: FtrProviderContext) { + const pageObjects = getPageObjects(['common', 'home', 'svlCommonPage']); + + // Failing - should be fixed with https://github.com/elastic/kibana/pull/164052 + describe.skip('Sample data in serverless', function () { + before(async () => { + await pageObjects.svlCommonPage.login(); + }); + + after(async () => { + await pageObjects.home.removeSampleDataSet('ecommerce'); + await pageObjects.svlCommonPage.forceLogout(); + }); + + it('Sample data loads', async () => { + await pageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', { + useActualUrl: true, + }); + await pageObjects.home.addSampleDataSet('ecommerce'); + const ecommerce = await pageObjects.home.isSampleDataSetInstalled('ecommerce'); + expect(ecommerce).toBe(true); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/index.examples.ts b/x-pack/test_serverless/functional/test_suites/common/index.examples.ts deleted file mode 100644 index 58ee2e2ac4478..0000000000000 --- a/x-pack/test_serverless/functional/test_suites/common/index.examples.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ loadTestFile }: FtrProviderContext) { - describe('serverless examples UI', function () { - this.tags('skipMKI'); - loadTestFile(require.resolve('./examples/data_view_field_editor_example')); - loadTestFile(require.resolve('./examples/discover_customization_examples')); - loadTestFile(require.resolve('./examples/field_formats')); - loadTestFile(require.resolve('./examples/partial_results')); - loadTestFile(require.resolve('./examples/search')); - loadTestFile(require.resolve('./examples/search_examples')); - loadTestFile(require.resolve('./examples/unified_field_list_examples')); - }); -} diff --git a/x-pack/test_serverless/functional/test_suites/common/index.ts b/x-pack/test_serverless/functional/test_suites/common/index.ts deleted file mode 100644 index 89fe34c19f640..0000000000000 --- a/x-pack/test_serverless/functional/test_suites/common/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ loadTestFile }: FtrProviderContext) { - describe('serverless common UI', function () { - loadTestFile(require.resolve('./home_page')); - loadTestFile(require.resolve('./management')); - - // platform security - loadTestFile(require.resolve('./security/api_keys')); - loadTestFile(require.resolve('./security/navigation/avatar_menu')); - - // Management - loadTestFile(require.resolve('./index_management')); - loadTestFile(require.resolve('./advanced_settings')); - - // Data View Management - loadTestFile(require.resolve('./data_view_mgmt')); - }); -} diff --git a/x-pack/test_serverless/functional/test_suites/common/management.ts b/x-pack/test_serverless/functional/test_suites/common/management.ts deleted file mode 100644 index 7ea23c7be4bb5..0000000000000 --- a/x-pack/test_serverless/functional/test_suites/common/management.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getPageObject, getService }: FtrProviderContext) { - const commonPage = getPageObject('common'); - const testSubjects = getService('testSubjects'); - - // Flaky in serverless tests - describe.skip('Management', function () { - describe('Disabled UIs', () => { - const DISABLED_PLUGINS = [ - { - appName: 'Upgrade Assistant', - url: 'stack/upgrade_assistant', - }, - { - appName: 'Advanced Settings', - url: 'kibana/settings', - }, - { - appName: 'Migrate', - url: 'data/migrate_data', - }, - { - appName: 'Remote Clusters', - url: 'data/remote_clusters', - }, - { - appName: 'Cross-Cluster Replication', - url: 'data/cross_cluster_replication', - }, - { - appName: 'Snapshot and Restore', - url: 'data/snapshot_restore', - }, - { - appName: 'Index Lifecycle Management', - url: 'data/index_lifecycle_management', - }, - { - appName: 'Rollup Jobs', - url: 'data/rollup_jobs', - }, - { - appName: 'License Management', - url: 'stack/license_management', - }, - { - appName: 'Watcher', - url: 'insightsAndAlerting/watcher', - }, - { - appName: 'Users', - url: 'security/users', - }, - { - appName: 'Roles', - url: 'security/roles', - }, - { - appName: 'Role Mappings', - url: 'security/role_mappings', - }, - ]; - - DISABLED_PLUGINS.forEach(({ appName, url }) => { - it(`${appName} is not accessible`, async () => { - await commonPage.navigateToUrl('management', url, { - shouldUseHashForSubUrl: false, - }); - // If the route doesn't exist, the user will be redirected back to the Management landing page - await testSubjects.exists('managementHome'); - }); - }); - }); - }); -} diff --git a/x-pack/test_serverless/functional/test_suites/common/advanced_settings.ts b/x-pack/test_serverless/functional/test_suites/common/management/advanced_settings.ts similarity index 96% rename from x-pack/test_serverless/functional/test_suites/common/advanced_settings.ts rename to x-pack/test_serverless/functional/test_suites/common/management/advanced_settings.ts index f24d3350b9744..0ea1e63397726 100644 --- a/x-pack/test_serverless/functional/test_suites/common/advanced_settings.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/advanced_settings.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { ALL_COMMON_SETTINGS } from '@kbn/serverless-common-settings'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); diff --git a/x-pack/test_serverless/functional/test_suites/common/data_view_mgmt.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_view_mgmt.ts similarity index 98% rename from x-pack/test_serverless/functional/test_suites/common/data_view_mgmt.ts rename to x-pack/test_serverless/functional/test_suites/common/management/data_view_mgmt.ts index 1b6972162f8ee..c8b004c65fb9b 100644 --- a/x-pack/test_serverless/functional/test_suites/common/data_view_mgmt.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_view_mgmt.ts @@ -9,7 +9,7 @@ import expect from 'expect'; import { DATA_VIEW_PATH } from '@kbn/data-views-plugin/server'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; const archivePath = 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index'; diff --git a/x-pack/test_serverless/functional/test_suites/common/management/disabled_uis.ts b/x-pack/test_serverless/functional/test_suites/common/management/disabled_uis.ts new file mode 100644 index 0000000000000..ca14928f525fc --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/disabled_uis.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getPageObject, getService }: FtrProviderContext) { + const commonPage = getPageObject('common'); + const testSubjects = getService('testSubjects'); + + // Flaky in serverless tests + describe.skip('Disabled UIs', function () { + const DISABLED_PLUGINS = [ + { + appName: 'Upgrade Assistant', + url: 'stack/upgrade_assistant', + }, + { + appName: 'Advanced Settings', + url: 'kibana/settings', + }, + { + appName: 'Migrate', + url: 'data/migrate_data', + }, + { + appName: 'Remote Clusters', + url: 'data/remote_clusters', + }, + { + appName: 'Cross-Cluster Replication', + url: 'data/cross_cluster_replication', + }, + { + appName: 'Snapshot and Restore', + url: 'data/snapshot_restore', + }, + { + appName: 'Index Lifecycle Management', + url: 'data/index_lifecycle_management', + }, + { + appName: 'Rollup Jobs', + url: 'data/rollup_jobs', + }, + { + appName: 'License Management', + url: 'stack/license_management', + }, + { + appName: 'Watcher', + url: 'insightsAndAlerting/watcher', + }, + { + appName: 'Users', + url: 'security/users', + }, + { + appName: 'Roles', + url: 'security/roles', + }, + { + appName: 'Role Mappings', + url: 'security/role_mappings', + }, + ]; + + DISABLED_PLUGINS.forEach(({ appName, url }) => { + it(`${appName} is not accessible`, async () => { + await commonPage.navigateToUrl('management', url, { + shouldUseHashForSubUrl: false, + }); + // If the route doesn't exist, the user will be redirected back to the Management landing page + await testSubjects.exists('managementHome'); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index.ts b/x-pack/test_serverless/functional/test_suites/common/management/index.ts new file mode 100644 index 0000000000000..83487bc5a0556 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext) => { + describe('Serverless Common UI - Management', function () { + loadTestFile(require.resolve('./index_management/index_templates')); + loadTestFile(require.resolve('./index_management/indices')); + loadTestFile(require.resolve('./index_management/create_enrich_policy')); + loadTestFile(require.resolve('./advanced_settings')); + loadTestFile(require.resolve('./data_view_mgmt')); + loadTestFile(require.resolve('./disabled_uis')); + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/common/index_management/create_enrich_policy.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/create_enrich_policy.ts similarity index 97% rename from x-pack/test_serverless/functional/test_suites/common/index_management/create_enrich_policy.ts rename to x-pack/test_serverless/functional/test_suites/common/management/index_management/create_enrich_policy.ts index 383e55f1e5579..bebe943459760 100644 --- a/x-pack/test_serverless/functional/test_suites/common/index_management/create_enrich_policy.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/create_enrich_policy.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['common', 'indexManagement', 'header', 'svlCommonPage']); diff --git a/x-pack/test_serverless/functional/test_suites/common/index_management/index_templates.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts similarity index 94% rename from x-pack/test_serverless/functional/test_suites/common/index_management/index_templates.ts rename to x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts index 7e9355076887b..e1ea8a50affc4 100644 --- a/x-pack/test_serverless/functional/test_suites/common/index_management/index_templates.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['svlCommonPage', 'common', 'indexManagement', 'header']); diff --git a/x-pack/test_serverless/functional/test_suites/common/index_management/indices.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/indices.ts similarity index 94% rename from x-pack/test_serverless/functional/test_suites/common/index_management/indices.ts rename to x-pack/test_serverless/functional/test_suites/common/management/index_management/indices.ts index 5d9d53863270b..e0ef321017b9e 100644 --- a/x-pack/test_serverless/functional/test_suites/common/index_management/indices.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/indices.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['svlCommonPage', 'common', 'indexManagement', 'header']); diff --git a/x-pack/test_serverless/functional/test_suites/common/security/api_keys.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/api_keys.ts similarity index 100% rename from x-pack/test_serverless/functional/test_suites/common/security/api_keys.ts rename to x-pack/test_serverless/functional/test_suites/common/platform_security/api_keys.ts diff --git a/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts new file mode 100644 index 0000000000000..bbcd138e20160 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Serverless Common UI - Platform Security', function () { + loadTestFile(require.resolve('./api_keys')); + loadTestFile(require.resolve('./navigation/avatar_menu')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/security/navigation/avatar_menu.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/navigation/avatar_menu.ts similarity index 100% rename from x-pack/test_serverless/functional/test_suites/common/security/navigation/avatar_menu.ts rename to x-pack/test_serverless/functional/test_suites/common/platform_security/navigation/avatar_menu.ts diff --git a/x-pack/test_serverless/functional/test_suites/common/sample_data.ts b/x-pack/test_serverless/functional/test_suites/common/sample_data.ts deleted file mode 100644 index a127ce0ee3e1d..0000000000000 --- a/x-pack/test_serverless/functional/test_suites/common/sample_data.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from 'expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['settings', 'common', 'header', 'home']); - - describe('Sample data in serverless', function () { - it('Sample data loads', async () => { - await PageObjects.home.addSampleDataSet('ecommerce'); - const ecommerce = await PageObjects.home.isSampleDataSetInstalled('ecommerce'); - expect(ecommerce).toBe(true); - }); - }); -} diff --git a/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts new file mode 100644 index 0000000000000..45f8bee6ad4f8 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/home_page'), + require.resolve('../../common/management'), + require.resolve('../../common/platform_security'), + ], + junit: { + reportName: 'Serverless Observability Functional Tests - Common Group 1', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.examples.ts b/x-pack/test_serverless/functional/test_suites/observability/config.examples.ts index 358dddbe89aca..49c8c5e421af6 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/config.examples.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/config.examples.ts @@ -12,7 +12,7 @@ import { createTestConfig } from '../../config.base'; export default createTestConfig({ serverlessProject: 'oblt', - testFiles: [require.resolve('../common/index.examples')], + testFiles: [require.resolve('../common/examples')], junit: { reportName: 'Serverless Observability Examples Functional Tests', }, @@ -20,4 +20,8 @@ export default createTestConfig({ resolve(REPO_ROOT, 'examples'), resolve(REPO_ROOT, 'x-pack/examples'), ]), + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml + esServerArgs: ['xpack.ml.dfa.enabled=false', 'xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/observability/config.feature_flags.ts index 31995ad616ca4..61a14189bbe22 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/config.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/config.feature_flags.ts @@ -21,4 +21,8 @@ export default createTestConfig({ kbnServerArgs: [], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml + esServerArgs: ['xpack.ml.dfa.enabled=false', 'xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.ts b/x-pack/test_serverless/functional/test_suites/observability/config.ts index 077dfff243735..725c7df80c1cb 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/config.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/config.ts @@ -9,9 +9,13 @@ import { createTestConfig } from '../../config.base'; export default createTestConfig({ serverlessProject: 'oblt', - testFiles: [require.resolve('../common'), require.resolve('.')], + testFiles: [require.resolve('.')], junit: { reportName: 'Serverless Observability Functional Tests', }, suiteTags: { exclude: ['skipSvlOblt'] }, + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml + esServerArgs: ['xpack.ml.dfa.enabled=false', 'xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts new file mode 100644 index 0000000000000..4e66fb384d786 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/home_page'), + require.resolve('../../common/management'), + require.resolve('../../common/platform_security'), + ], + junit: { + reportName: 'Serverless Search Functional Tests - Common Group 1', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/search/config.examples.ts b/x-pack/test_serverless/functional/test_suites/search/config.examples.ts index eb7e66d8a3786..67c77ac423844 100644 --- a/x-pack/test_serverless/functional/test_suites/search/config.examples.ts +++ b/x-pack/test_serverless/functional/test_suites/search/config.examples.ts @@ -12,7 +12,7 @@ import { createTestConfig } from '../../config.base'; export default createTestConfig({ serverlessProject: 'es', - testFiles: [require.resolve('../common/index.examples')], + testFiles: [require.resolve('../common/examples')], junit: { reportName: 'Serverless Search Examples Functional Tests', }, @@ -20,4 +20,8 @@ export default createTestConfig({ resolve(REPO_ROOT, 'examples'), resolve(REPO_ROOT, 'x-pack/examples'), ]), + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/esproject/config/elasticsearch.yml + esServerArgs: ['xpack.ml.ad.enabled=false', 'xpack.ml.dfa.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts index e93c3ff2f02e5..9d9663be9230f 100644 --- a/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts @@ -21,4 +21,8 @@ export default createTestConfig({ kbnServerArgs: [], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/esproject/config/elasticsearch.yml + esServerArgs: ['xpack.ml.ad.enabled=false', 'xpack.ml.dfa.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/test_suites/search/config.screenshots.ts b/x-pack/test_serverless/functional/test_suites/search/config.screenshots.ts index fd53eda92aa5e..b0c951ef3295c 100644 --- a/x-pack/test_serverless/functional/test_suites/search/config.screenshots.ts +++ b/x-pack/test_serverless/functional/test_suites/search/config.screenshots.ts @@ -16,4 +16,8 @@ export default createTestConfig({ junit: { reportName: 'Serverless Search Screenshot Creation', }, + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/esproject/config/elasticsearch.yml + esServerArgs: ['xpack.ml.ad.enabled=false', 'xpack.ml.dfa.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/test_suites/search/config.ts b/x-pack/test_serverless/functional/test_suites/search/config.ts index 124a4fc90a9e6..5e0168a7c530d 100644 --- a/x-pack/test_serverless/functional/test_suites/search/config.ts +++ b/x-pack/test_serverless/functional/test_suites/search/config.ts @@ -9,9 +9,13 @@ import { createTestConfig } from '../../config.base'; export default createTestConfig({ serverlessProject: 'es', - testFiles: [require.resolve('../common'), require.resolve('.')], + testFiles: [require.resolve('.')], junit: { reportName: 'Serverless Search Functional Tests', }, suiteTags: { exclude: ['skipSvlSearch'] }, + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/esproject/config/elasticsearch.yml + esServerArgs: ['xpack.ml.ad.enabled=false', 'xpack.ml.dfa.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts new file mode 100644 index 0000000000000..263cae265a51c --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/home_page'), + require.resolve('../../common/management'), + require.resolve('../../common/platform_security'), + ], + junit: { + reportName: 'Serverless Security Functional Tests - Common Group 1', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/security/config.examples.ts b/x-pack/test_serverless/functional/test_suites/security/config.examples.ts index 7be037baa9c9a..a6f666474f996 100644 --- a/x-pack/test_serverless/functional/test_suites/security/config.examples.ts +++ b/x-pack/test_serverless/functional/test_suites/security/config.examples.ts @@ -12,7 +12,7 @@ import { createTestConfig } from '../../config.base'; export default createTestConfig({ serverlessProject: 'security', - testFiles: [require.resolve('../common/index.examples')], + testFiles: [require.resolve('../common/examples')], junit: { reportName: 'Serverless Security Examples Functional Tests', }, @@ -20,4 +20,8 @@ export default createTestConfig({ resolve(REPO_ROOT, 'examples'), resolve(REPO_ROOT, 'x-pack/examples'), ]), + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/security/config/elasticsearch.yml + esServerArgs: ['xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/test_suites/security/config.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/security/config.feature_flags.ts index 735c8a8765d16..44636d99c21f9 100644 --- a/x-pack/test_serverless/functional/test_suites/security/config.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/security/config.feature_flags.ts @@ -21,4 +21,8 @@ export default createTestConfig({ kbnServerArgs: [], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/security/config/elasticsearch.yml + esServerArgs: ['xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/functional/test_suites/security/config.ts b/x-pack/test_serverless/functional/test_suites/security/config.ts index e255310c61b28..3226bd7cef857 100644 --- a/x-pack/test_serverless/functional/test_suites/security/config.ts +++ b/x-pack/test_serverless/functional/test_suites/security/config.ts @@ -9,9 +9,13 @@ import { createTestConfig } from '../../config.base'; export default createTestConfig({ serverlessProject: 'security', - testFiles: [require.resolve('../common'), require.resolve('.')], + testFiles: [require.resolve('.')], junit: { reportName: 'Serverless Security Functional Tests', }, suiteTags: { exclude: ['skipSvlSec'] }, + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/security/config/elasticsearch.yml + esServerArgs: ['xpack.ml.nlp.enabled=false'], }); diff --git a/x-pack/test_serverless/shared/types/index.ts b/x-pack/test_serverless/shared/types/index.ts index 0a36e71db7c39..716c389db666d 100644 --- a/x-pack/test_serverless/shared/types/index.ts +++ b/x-pack/test_serverless/shared/types/index.ts @@ -9,6 +9,7 @@ import { InheritedServices } from '../../api_integration/services'; export interface CreateTestConfigOptions { serverlessProject: 'es' | 'oblt' | 'security'; + esServerArgs?: string[]; kbnServerArgs?: string[]; testFiles: string[]; junit: { reportName: string };