From ac0b0b4f05876f1c66f5b4fde7965a1955b90ec0 Mon Sep 17 00:00:00 2001 From: Kurt Date: Tue, 19 Nov 2024 08:31:47 -0500 Subject: [PATCH] Enabling Full FTR, Integration, and Unit tests to the FIPS Test Pipeline (#192632) ## Summary Closes #192233 Just in time for Thanksgiving - a full buffet of FIPS testing fixes Usage of non-compliant algorithms manifest as runtime errors, so it is imperative that we attempt to run all tests possible with Kibana in FIPS mode. However, several overrides are needed to run Kibana in FIPS mode, resulting in setup that make it impossible to run. ## In this PR - Enable Unit tests for FIPS pipeline - Enable Integration Tests for FIPS pipeline - Enable Full FTR suite for FIPS pipeline (smoke test had originally run a subset) - Skip tests that break with overrides - Fix/change tests to work in FIPS mode to maximize coverage - Examine necessity of MD5 when installing from source (TBD based Ops PR feed back, see self review below) - Remove md5 from es_file_client options ## Latest Successful FIPS Test Run https://buildkite.com/elastic/kibana-fips/builds/268 --------- Co-authored-by: Brad White Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Aleh Zasypkin Co-authored-by: Larry Gregory --- .buildkite/pipelines/fips.yml | 7 +- .buildkite/scripts/steps/fips/smoke_test.sh | 24 -- .../scripts/steps/test/jest_parallel.sh | 9 +- .../src/security_service.test.ts | 26 +- .../tsconfig.json | 1 + .../src/create_root.ts | 24 +- .../tsconfig.json | 1 + packages/kbn-es/src/install/install_source.ts | 4 +- packages/kbn-test/src/es/test_es_cluster.ts | 6 +- .../config/check_dynamic_config.test.ts | 233 +++++++++--------- .../config/config_deprecation.test.ts | 21 +- .../default_route_provider_config.test.ts | 111 +++++---- .../version_compatibility.test.ts | 17 +- .../integration_tests/node/migrator.test.ts | 4 +- .../group3/multiple_es_nodes.test.ts | 167 +++++++------ .../migrations/group3/read_batch_size.test.ts | 51 ++-- .../serverless/migrations/smoke.test.ts | 39 +-- .../build/lib/integration_tests/fs.test.ts | 10 +- .../adapters/es/integration_tests/es.test.ts | 7 +- .../file_client/create_es_file_client.ts | 9 +- .../integration_tests/es_file_client.test.ts | 15 +- .../file_hash_transform.test.ts | 40 +-- .../group5/dashboard_panel_listing.ts | 3 +- .../http/ssl_with_p12/index.js | 3 +- .../http/ssl_with_p12_intermediate/index.js | 3 +- .../axios_utils_connection.test.ts | 51 ++-- .../plugins/fleet/.storybook/smoke.test.tsx | 32 ++- .../services/preconfiguration/outputs.ts | 1 - .../read_only_view.ts | 1 + 29 files changed, 520 insertions(+), 400 deletions(-) delete mode 100755 .buildkite/scripts/steps/fips/smoke_test.sh diff --git a/.buildkite/pipelines/fips.yml b/.buildkite/pipelines/fips.yml index f4a5b3623bbcc..e04a5ecb8f936 100644 --- a/.buildkite/pipelines/fips.yml +++ b/.buildkite/pipelines/fips.yml @@ -40,14 +40,15 @@ steps: machineType: n2-standard-2 preemptible: true - - command: .buildkite/scripts/steps/fips/smoke_test.sh - label: 'Pick Smoke Test Group Run Order' + - command: .buildkite/scripts/steps/test/pick_test_group_run_order.sh + label: 'Pick Test Group Run Order' depends_on: build timeout_in_minutes: 10 env: FTR_CONFIGS_SCRIPT: '.buildkite/scripts/steps/test/ftr_configs.sh' FTR_EXTRA_ARGS: '$FTR_EXTRA_ARGS' - LIMIT_CONFIG_TYPE: 'functional' + JEST_UNIT_SCRIPT: '.buildkite/scripts/steps/test/jest.sh' + JEST_INTEGRATION_SCRIPT: '.buildkite/scripts/steps/test/jest_integration.sh' retry: automatic: - exit_status: '*' diff --git a/.buildkite/scripts/steps/fips/smoke_test.sh b/.buildkite/scripts/steps/fips/smoke_test.sh deleted file mode 100755 index 685bb111ff81a..0000000000000 --- a/.buildkite/scripts/steps/fips/smoke_test.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# Limit the FTR configs for now to avoid running all the tests. Once we're -# ready to utilize the full FTR suite in FIPS mode, we can remove this file and -# call pick_test_group_run_order.sh directly in .buildkite/pipelines/fips.yml. -configs=( - "x-pack/test/reporting_functional/reporting_and_security.config.ts" - "x-pack/test/saved_object_api_integration/security_and_spaces/config_trial.ts" - "x-pack/test/alerting_api_integration/security_and_spaces/group1/config.ts" - "x-pack/test/alerting_api_integration/security_and_spaces/group2/config.ts" - "x-pack/test/alerting_api_integration/security_and_spaces/group3/config.ts" - "x-pack/test/alerting_api_integration/security_and_spaces/group4/config.ts" - "x-pack/test/functional/apps/saved_objects_management/config.ts" - "x-pack/test/functional/apps/user_profiles/config.ts" - "x-pack/test/functional/apps/security/config.ts" -) - -printf -v FTR_CONFIG_PATTERNS '%s,' "${configs[@]}" -FTR_CONFIG_PATTERNS="${FTR_CONFIG_PATTERNS%,}" -export FTR_CONFIG_PATTERNS - -.buildkite/scripts/steps/test/pick_test_group_run_order.sh diff --git a/.buildkite/scripts/steps/test/jest_parallel.sh b/.buildkite/scripts/steps/test/jest_parallel.sh index 2a7cf780f5787..648c3b225141d 100755 --- a/.buildkite/scripts/steps/test/jest_parallel.sh +++ b/.buildkite/scripts/steps/test/jest_parallel.sh @@ -60,7 +60,14 @@ while read -r config; do # --trace-warnings to debug # Node.js process-warning detected: # Warning: Closing file descriptor 24 on garbage collection - cmd="NODE_OPTIONS=\"--max-old-space-size=12288 --trace-warnings\" node ./scripts/jest --config=\"$config\" $parallelism --coverage=false --passWithNoTests" + cmd="NODE_OPTIONS=\"--max-old-space-size=12288 --trace-warnings" + + if [ "${KBN_ENABLE_FIPS:-}" == "true" ]; then + cmd=$cmd" --enable-fips --openssl-config=$HOME/nodejs.cnf" + fi + + cmd=$cmd"\" node ./scripts/jest --config=\"$config\" $parallelism --coverage=false --passWithNoTests" + echo "actual full command is:" echo "$cmd" echo "" diff --git a/packages/core/security/core-security-server-internal/src/security_service.test.ts b/packages/core/security/core-security-server-internal/src/security_service.test.ts index 75539e9954ac0..0ff1e59db71ec 100644 --- a/packages/core/security/core-security-server-internal/src/security_service.test.ts +++ b/packages/core/security/core-security-server-internal/src/security_service.test.ts @@ -16,17 +16,32 @@ import { loggerMock, MockedLogger } from '@kbn/logging-mocks'; import { mockCoreContext } from '@kbn/core-base-server-mocks'; import type { CoreSecurityDelegateContract } from '@kbn/core-security-server'; import { SecurityService } from './security_service'; +import { configServiceMock } from '@kbn/config-mocks'; +import { getFips } from 'crypto'; const createStubInternalContract = (): CoreSecurityDelegateContract => { return Symbol('stubContract') as unknown as CoreSecurityDelegateContract; }; -describe('SecurityService', () => { +describe('SecurityService', function () { let coreContext: ReturnType; + let configService: ReturnType; let service: SecurityService; beforeEach(() => { - coreContext = mockCoreContext.create(); + const mockConfig = { + xpack: { + security: { + experimental: { + fipsMode: { + enabled: !!getFips(), + }, + }, + }, + }, + }; + configService = configServiceMock.create({ getConfig$: mockConfig }); + coreContext = mockCoreContext.create({ configService }); service = new SecurityService(coreContext); convertSecurityApiMock.mockReset(); @@ -51,8 +66,11 @@ describe('SecurityService', () => { describe('#isEnabled', () => { it('should return boolean', () => { const { fips } = service.setup(); - - expect(fips.isEnabled()).toBe(false); + if (getFips() === 0) { + expect(fips.isEnabled()).toBe(false); + } else { + expect(fips.isEnabled()).toBe(true); + } }); }); }); diff --git a/packages/core/security/core-security-server-internal/tsconfig.json b/packages/core/security/core-security-server-internal/tsconfig.json index e1812dc77cf49..11128461daf4e 100644 --- a/packages/core/security/core-security-server-internal/tsconfig.json +++ b/packages/core/security/core-security-server-internal/tsconfig.json @@ -22,5 +22,6 @@ "@kbn/core-base-server-mocks", "@kbn/config", "@kbn/core-logging-server-mocks", + "@kbn/config-mocks", ] } diff --git a/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_root.ts b/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_root.ts index d2fa6850a8bf8..38dae90905cb2 100644 --- a/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_root.ts +++ b/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_root.ts @@ -12,10 +12,12 @@ import loadJsonFile from 'load-json-file'; import { defaultsDeep } from 'lodash'; import { BehaviorSubject } from 'rxjs'; import supertest from 'supertest'; +import { set } from '@kbn/safer-lodash-set'; import { getPackages } from '@kbn/repo-packages'; import { ToolingLog } from '@kbn/tooling-log'; import { REPO_ROOT } from '@kbn/repo-info'; +import { getFips } from 'crypto'; import { createTestEsCluster, CreateTestEsClusterOptions, @@ -75,6 +77,17 @@ export function createRootWithSettings( pkg.version = customKibanaVersion; } + /* + * Most of these integration tests expect OSS to default to true, but FIPS + * requires the security plugin to be enabled + */ + let oss = true; + if (getFips() === 1) { + set(settings, 'xpack.security.experimental.fipsMode.enabled', true); + oss = false; + delete cliArgs.oss; + } + const env = Env.createDefault( REPO_ROOT, { @@ -84,10 +97,10 @@ export function createRootWithSettings( watch: false, basePath: false, runExamples: false, - oss: true, disableOptimizer: true, cache: true, dist: false, + oss, ...cliArgs, }, repoPackages: getPackages(REPO_ROOT), @@ -255,7 +268,13 @@ export function createTestServers({ if (!adjustTimeout) { throw new Error('adjustTimeout is required in order to avoid flaky tests'); } - const license = settings.es?.license ?? 'basic'; + let license = settings.es?.license ?? 'basic'; + + if (getFips() === 1) { + // Set license to 'trial' if Node is running in FIPS mode + license = 'trial'; + } + const usersToBeAdded = settings.users ?? []; if (usersToBeAdded.length > 0) { if (license !== 'trial') { @@ -292,6 +311,7 @@ export function createTestServers({ hosts: es.getHostUrls(), username: kibanaServerTestUser.username, password: kibanaServerTestUser.password, + ...(getFips() ? kbnSettings.elasticsearch : {}), }; } diff --git a/packages/core/test-helpers/core-test-helpers-kbn-server/tsconfig.json b/packages/core/test-helpers/core-test-helpers-kbn-server/tsconfig.json index 85d14bb04ab59..65ca0ccdfca0b 100644 --- a/packages/core/test-helpers/core-test-helpers-kbn-server/tsconfig.json +++ b/packages/core/test-helpers/core-test-helpers-kbn-server/tsconfig.json @@ -20,6 +20,7 @@ "@kbn/repo-packages", "@kbn/es", "@kbn/dev-utils", + "@kbn/safer-lodash-set", ], "exclude": [ "target/**/*", diff --git a/packages/kbn-es/src/install/install_source.ts b/packages/kbn-es/src/install/install_source.ts index 244b349002829..9a7e8f166791a 100644 --- a/packages/kbn-es/src/install/install_source.ts +++ b/packages/kbn-es/src/install/install_source.ts @@ -84,7 +84,7 @@ async function sourceInfo(cwd: string, license: string, log: ToolingLog = defaul log.info('on %s at %s', chalk.bold(branch), chalk.bold(sha)); log.info('%s locally modified file(s)', chalk.bold(status.modified.length)); - const etag = crypto.createHash('md5').update(branch); // eslint-disable-line @kbn/eslint/no_unsafe_hash + const etag = crypto.createHash('sha256').update(branch); etag.update(sha); // for changed files, use last modified times in hash calculation @@ -92,7 +92,7 @@ async function sourceInfo(cwd: string, license: string, log: ToolingLog = defaul etag.update(fs.statSync(path.join(cwd, file.path)).mtime.toString()); }); - const cwdHash = crypto.createHash('md5').update(cwd).digest('hex').substr(0, 8); // eslint-disable-line @kbn/eslint/no_unsafe_hash + const cwdHash = crypto.createHash('sha256').update(cwd).digest('hex').substr(0, 8); const basename = `${branch}-${task}-${cwdHash}`; const filename = `${basename}.${ext}`; diff --git a/packages/kbn-test/src/es/test_es_cluster.ts b/packages/kbn-test/src/es/test_es_cluster.ts index 620147e1fa7ab..20c54e044e46f 100644 --- a/packages/kbn-test/src/es/test_es_cluster.ts +++ b/packages/kbn-test/src/es/test_es_cluster.ts @@ -21,6 +21,7 @@ import type { ToolingLog } from '@kbn/tooling-log'; import { REPO_ROOT } from '@kbn/repo-info'; import type { ArtifactLicense } from '@kbn/es'; import type { ServerlessOptions } from '@kbn/es/src/utils'; +import { getFips } from 'crypto'; import { CI_PARALLEL_PROCESS_PREFIX } from '../ci_parallel_process_prefix'; import { esTestConfig } from './es_test_config'; @@ -200,12 +201,15 @@ export function createTestEsCluster< const esArgs = assignArgs(defaultEsArgs, customEsArgs); + // Use 'trial' license if FIPS mode is enabled, otherwise use the provided license or default to 'basic' + const testLicense: ArtifactLicense = getFips() === 1 ? 'trial' : license ? license : 'basic'; + const config = { version: esVersion, installPath: Path.resolve(basePath, clusterName), sourcePath: Path.resolve(REPO_ROOT, '../elasticsearch'), + license: testLicense, password, - license, basePath, esArgs, resources: files, diff --git a/src/core/server/integration_tests/config/check_dynamic_config.test.ts b/src/core/server/integration_tests/config/check_dynamic_config.test.ts index 85061b876eebf..38250076385b9 100644 --- a/src/core/server/integration_tests/config/check_dynamic_config.test.ts +++ b/src/core/server/integration_tests/config/check_dynamic_config.test.ts @@ -16,128 +16,135 @@ import { request, } from '@kbn/core-test-helpers-kbn-server'; import { PLUGIN_SYSTEM_ENABLE_ALL_PLUGINS_CONFIG_PATH } from '@kbn/core-plugins-server-internal/src/constants'; - -describe('PUT /internal/core/_settings', () => { - let esServer: TestElasticsearchUtils; - let root: Root; - - const loggerName = 'my-test-logger'; - - beforeAll(async () => { - const settings = { - coreApp: { allowDynamicConfigOverrides: true }, - logging: { - loggers: [{ name: loggerName, level: 'error', appenders: ['console'] }], - }, - server: { restrictInternalApis: false }, - }; - const { startES, startKibana } = createTestServers({ - adjustTimeout: (t: number) => jest.setTimeout(t), - settings: { - kbn: settings, - }, +import { getFips } from 'crypto'; + +if (getFips() === 0) { + describe('PUT /internal/core/_settings', () => { + let esServer: TestElasticsearchUtils; + let root: Root; + + const loggerName = 'my-test-logger'; + + beforeAll(async () => { + const settings = { + coreApp: { allowDynamicConfigOverrides: true }, + logging: { + loggers: [{ name: loggerName, level: 'error', appenders: ['console'] }], + }, + server: { restrictInternalApis: false }, + }; + const { startES, startKibana } = createTestServers({ + adjustTimeout: (t: number) => jest.setTimeout(t), + settings: { + kbn: settings, + }, + }); + + esServer = await startES(); + + const kbnUtils = await startKibana(); + root = kbnUtils.root; + + // eslint-disable-next-line dot-notation + root['server'].configService.addDynamicConfigPaths('logging', ['loggers']); // just for the sake of being able to change something easy to test }); - esServer = await startES(); - - const kbnUtils = await startKibana(); - root = kbnUtils.root; - - // eslint-disable-next-line dot-notation - root['server'].configService.addDynamicConfigPaths('logging', ['loggers']); // just for the sake of being able to change something easy to test - }); + afterAll(async () => { + await root?.shutdown(); + await esServer?.stop(); + }); - afterAll(async () => { - await root?.shutdown(); - await esServer?.stop(); - }); + test('should update the log level', async () => { + const logger = root.logger.get(loggerName); + expect(logger.isLevelEnabled('info')).toBe(false); + await request + .put(root, '/internal/core/_settings') + .set('Elastic-Api-Version', '1') + .send({ 'logging.loggers': [{ name: loggerName, level: 'debug', appenders: ['console'] }] }) + .expect(200); + expect(logger.isLevelEnabled('info')).toBe(true); + }); - test('should update the log level', async () => { - const logger = root.logger.get(loggerName); - expect(logger.isLevelEnabled('info')).toBe(false); - await request - .put(root, '/internal/core/_settings') - .set('Elastic-Api-Version', '1') - .send({ 'logging.loggers': [{ name: loggerName, level: 'debug', appenders: ['console'] }] }) - .expect(200); - expect(logger.isLevelEnabled('info')).toBe(true); + test('should remove the setting', async () => { + const logger = root.logger.get(loggerName); + expect(logger.isLevelEnabled('info')).toBe(true); // still true from the previous test + await request + .put(root, '/internal/core/_settings') + .set('Elastic-Api-Version', '1') + .send({ 'logging.loggers': null }) + .expect(200); + expect(logger.isLevelEnabled('info')).toBe(false); + }); }); - test('should remove the setting', async () => { - const logger = root.logger.get(loggerName); - expect(logger.isLevelEnabled('info')).toBe(true); // still true from the previous test - await request - .put(root, '/internal/core/_settings') - .set('Elastic-Api-Version', '1') - .send({ 'logging.loggers': null }) - .expect(200); - expect(logger.isLevelEnabled('info')).toBe(false); - }); -}); - -describe('checking all opted-in dynamic config settings', () => { - let root: Root; - - beforeAll(async () => { - const settings = { - logging: { - loggers: [{ name: 'root', level: 'info', appenders: ['console'] }], - }, - server: { - restrictInternalApis: false, - }, - }; - - set(settings, PLUGIN_SYSTEM_ENABLE_ALL_PLUGINS_CONFIG_PATH, true); - - root = createRootWithCorePlugins(settings, { - basePath: false, - cache: false, - dev: true, - disableOptimizer: true, - silent: false, - dist: false, - oss: false, - runExamples: false, - watch: false, + describe('checking all opted-in dynamic config settings', () => { + let root: Root; + + beforeAll(async () => { + const settings = { + logging: { + loggers: [{ name: 'root', level: 'info', appenders: ['console'] }], + }, + server: { + restrictInternalApis: false, + }, + }; + + set(settings, PLUGIN_SYSTEM_ENABLE_ALL_PLUGINS_CONFIG_PATH, true); + + root = createRootWithCorePlugins(settings, { + basePath: false, + cache: false, + dev: true, + disableOptimizer: true, + silent: false, + dist: false, + oss: false, + runExamples: false, + watch: false, + }); + + await root.preboot(); + await root.setup(); }); - await root.preboot(); - await root.setup(); - }); + afterAll(async () => { + if (root) { + await root.shutdown(); + } + }); - afterAll(async () => { - if (root) { - await root.shutdown(); + function getListOfDynamicConfigPaths(): string[] { + // eslint-disable-next-line dot-notation + return [...root['server']['configService']['dynamicPaths'].entries()] + .flatMap(([configPath, dynamicConfigKeys]) => { + return dynamicConfigKeys.map( + (dynamicConfigKey: string) => `${configPath}.${dynamicConfigKey}` + ); + }) + .sort(); } - }); - function getListOfDynamicConfigPaths(): string[] { - // eslint-disable-next-line dot-notation - return [...root['server']['configService']['dynamicPaths'].entries()] - .flatMap(([configPath, dynamicConfigKeys]) => { - return dynamicConfigKeys.map( - (dynamicConfigKey: string) => `${configPath}.${dynamicConfigKey}` - ); - }) - .sort(); - } - - /** - * This test is meant to fail when any setting is flagged as capable - * of dynamic configuration {@link PluginConfigDescriptor.dynamicConfig}. - * - * Please, add your settings to the list with a comment of why it's required to be dynamic. - * - * The intent is to trigger a code review from the Core and Security teams to discuss potential issues. - */ - test('detecting all the settings that have opted-in for dynamic in-memory updates', () => { - expect(getListOfDynamicConfigPaths()).toStrictEqual([ - // Making testing easier by having the ability of overriding the feature flags without the need to restart - 'feature_flags.overrides', - // We need this for enriching our Perf tests with more valuable data regarding the steps of the test - // Also helpful in Cloud & Serverless testing because we can't control the labels in those offerings - 'telemetry.labels', - ]); + /** + * This test is meant to fail when any setting is flagged as capable + * of dynamic configuration {@link PluginConfigDescriptor.dynamicConfig}. + * + * Please, add your settings to the list with a comment of why it's required to be dynamic. + * + * The intent is to trigger a code review from the Core and Security teams to discuss potential issues. + */ + test('detecting all the settings that have opted-in for dynamic in-memory updates', () => { + expect(getListOfDynamicConfigPaths()).toStrictEqual([ + // Making testing easier by having the ability of overriding the feature flags without the need to restart + 'feature_flags.overrides', + // We need this for enriching our Perf tests with more valuable data regarding the steps of the test + // Also helpful in Cloud & Serverless testing because we can't control the labels in those offerings + 'telemetry.labels', + ]); + }); + }); +} else { + it('is running in FIPS mode, skipping tests since they fail due to FIPS overrides', () => { + expect(getFips()).toBe(1); }); -}); +} diff --git a/src/core/server/integration_tests/config/config_deprecation.test.ts b/src/core/server/integration_tests/config/config_deprecation.test.ts index 277a6080c377f..42425f10a4c97 100644 --- a/src/core/server/integration_tests/config/config_deprecation.test.ts +++ b/src/core/server/integration_tests/config/config_deprecation.test.ts @@ -10,6 +10,7 @@ import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { mockLoggingSystem } from './config_deprecation.test.mocks'; import { createRoot } from '@kbn/core-test-helpers-kbn-server'; +import { getFips } from 'crypto'; describe('configuration deprecations', () => { let root: ReturnType; @@ -24,13 +25,19 @@ describe('configuration deprecations', () => { } }); - it('should not log deprecation warnings for default configuration', async () => { - root = createRoot(); + if (getFips() === 0) { + it('should not log deprecation warnings for default configuration', async () => { + root = createRoot(); - await root.preboot(); - await root.setup(); + await root.preboot(); + await root.setup(); - const logs = loggingSystemMock.collect(mockLoggingSystem); - expect(logs.warn.flat()).toHaveLength(0); - }); + const logs = loggingSystemMock.collect(mockLoggingSystem); + expect(logs.warn.flat()).toHaveLength(0); + }); + } else { + it('fips is enabled and the default configuration has been overridden', () => { + expect(getFips()).toBe(1); + }); + } }); diff --git a/src/core/server/integration_tests/core_app/default_route_provider_config.test.ts b/src/core/server/integration_tests/core_app/default_route_provider_config.test.ts index 57646007a586f..a3338e7d45468 100644 --- a/src/core/server/integration_tests/core_app/default_route_provider_config.test.ts +++ b/src/core/server/integration_tests/core_app/default_route_provider_config.test.ts @@ -14,74 +14,81 @@ import { request, type TestElasticsearchUtils, } from '@kbn/core-test-helpers-kbn-server'; +import { getFips } from 'crypto'; describe('default route provider', () => { let esServer: TestElasticsearchUtils; let root: Root; - beforeAll(async () => { - const { startES } = createTestServers({ - adjustTimeout: (t: number) => jest.setTimeout(t), + if (getFips() === 0) { + beforeAll(async () => { + const { startES } = createTestServers({ + adjustTimeout: (t: number) => jest.setTimeout(t), + }); + esServer = await startES(); + root = createRootWithCorePlugins({ + server: { + basePath: '/hello', + restrictInternalApis: false, + }, + }); + + await root.preboot(); + await root.setup(); + await root.start(); }); - esServer = await startES(); - root = createRootWithCorePlugins({ - server: { - basePath: '/hello', - restrictInternalApis: false, - }, + + afterAll(async () => { + await esServer.stop(); + await root.shutdown(); }); - await root.preboot(); - await root.setup(); - await root.start(); - }); + it('redirects to the configured default route respecting basePath', async function () { + const { status, header } = await request.get(root, '/'); - afterAll(async () => { - await esServer.stop(); - await root.shutdown(); - }); + expect(status).toEqual(302); + expect(header).toMatchObject({ + location: '/hello/app/home', + }); + }); - it('redirects to the configured default route respecting basePath', async function () { - const { status, header } = await request.get(root, '/'); + it('ignores invalid values', async function () { + const invalidRoutes = [ + 'http://not-your-kibana.com', + '///example.com', + '//example.com', + ' //example.com', + ]; - expect(status).toEqual(302); - expect(header).toMatchObject({ - location: '/hello/app/home', - }); - }); + for (const url of invalidRoutes) { + await request + .post(root, '/internal/kibana/settings/defaultRoute') + .send({ value: url }) + .expect(400); + } - it('ignores invalid values', async function () { - const invalidRoutes = [ - 'http://not-your-kibana.com', - '///example.com', - '//example.com', - ' //example.com', - ]; + const { status, header } = await request.get(root, '/'); + expect(status).toEqual(302); + expect(header).toMatchObject({ + location: '/hello/app/home', + }); + }); - for (const url of invalidRoutes) { + it('consumes valid values', async function () { await request .post(root, '/internal/kibana/settings/defaultRoute') - .send({ value: url }) - .expect(400); - } + .send({ value: '/valid' }) + .expect(200); - const { status, header } = await request.get(root, '/'); - expect(status).toEqual(302); - expect(header).toMatchObject({ - location: '/hello/app/home', + const { status, header } = await request.get(root, '/'); + expect(status).toEqual(302); + expect(header).toMatchObject({ + location: '/hello/valid', + }); }); - }); - - it('consumes valid values', async function () { - await request - .post(root, '/internal/kibana/settings/defaultRoute') - .send({ value: '/valid' }) - .expect(200); - - const { status, header } = await request.get(root, '/'); - expect(status).toEqual(302); - expect(header).toMatchObject({ - location: '/hello/valid', + } else { + it('should have fips enabled, the overrides prevent these tests from working', () => { + expect(getFips()).toBe(1); }); - }); + } }); diff --git a/src/core/server/integration_tests/elasticsearch/version_compatibility.test.ts b/src/core/server/integration_tests/elasticsearch/version_compatibility.test.ts index d63895220ceb1..c2cb6fccc3cd0 100644 --- a/src/core/server/integration_tests/elasticsearch/version_compatibility.test.ts +++ b/src/core/server/integration_tests/elasticsearch/version_compatibility.test.ts @@ -17,6 +17,7 @@ import { firstValueFrom, Subject } from 'rxjs'; import { CliArgs } from '@kbn/config'; import Semver from 'semver'; import { unsafeConsole } from '@kbn/security-hardening'; +import { getFips } from 'crypto'; function nextMinor() { return Semver.inc(esTestConfig.getVersion(), 'minor') || '10.0.0'; @@ -130,9 +131,15 @@ describe('Version Compatibility', () => { ); }); - it('should ignore version mismatch when running on serverless mode and complete startup', async () => { - await expect( - startServers({ customKibanaVersion: nextMinor(), cliArgs: { serverless: true } }) - ).resolves.toBeUndefined(); - }); + if (getFips() === 0) { + it('should ignore version mismatch when running on serverless mode and complete startup', async () => { + await expect( + startServers({ customKibanaVersion: nextMinor(), cliArgs: { serverless: true } }) + ).resolves.toBeUndefined(); + }); + } else { + it('fips is enabled, serverless doesnt like the config overrides', () => { + expect(getFips()).toBe(1); + }); + } }); diff --git a/src/core/server/integration_tests/node/migrator.test.ts b/src/core/server/integration_tests/node/migrator.test.ts index cd4ab1cd8c74e..f899d7da5cde0 100644 --- a/src/core/server/integration_tests/node/migrator.test.ts +++ b/src/core/server/integration_tests/node/migrator.test.ts @@ -16,6 +16,7 @@ import { ToolingLog } from '@kbn/tooling-log'; import { createTestEsCluster, kibanaServerTestUser } from '@kbn/test'; import { observeLines } from '@kbn/stdio-dev-helpers'; import { REPO_ROOT } from '@kbn/repo-info'; +import { getFips } from 'crypto'; describe('migrator-only node', () => { const log = new ToolingLog({ writeTo: process.stdout, level: 'debug' }); @@ -30,6 +31,7 @@ describe('migrator-only node', () => { let logsSub: undefined | Rx.Subscription; try { await es.start(); + const isFipsEnabled = getFips(); proc = ChildProcess.spawn( process.execPath, @@ -42,7 +44,7 @@ describe('migrator-only node', () => { '--no-optimizer', '--no-base-path', '--no-watch', - '--oss', + isFipsEnabled ? '--xpack.security.experimental.fipsMode.enabled=true' : '--oss', ], { stdio: ['pipe', 'pipe', 'pipe'] } ); diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/multiple_es_nodes.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/multiple_es_nodes.test.ts index 490dea4c06be6..6898962077b9c 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/multiple_es_nodes.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/multiple_es_nodes.test.ts @@ -18,6 +18,7 @@ import { } from '@kbn/core-test-helpers-kbn-server'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { Root } from '@kbn/core-root-server-internal'; +import { getFips } from 'crypto'; const LOG_FILE_PREFIX = 'migration_test_multiple_es_nodes'; @@ -114,89 +115,95 @@ describe('migration v2', () => { } }); - it('migrates saved objects normally with multiple ES nodes', async () => { - const { startES } = createTestServers({ - adjustTimeout: (t: number) => jest.setTimeout(t), - settings: { - es: { - license: 'basic', - clusterName: 'es-test-cluster', - nodes: [ - { - name: 'node-01', - // original SO (5000 total; 2500 of type `foo` + 2500 of type `bar`): - // [ - // { id: 'foo:1', type: 'foo', foo: { status: 'not_migrated_1' } }, - // { id: 'bar:1', type: 'bar', bar: { status: 'not_migrated_1' } }, - // { id: 'foo:2', type: 'foo', foo: { status: 'not_migrated_2' } }, - // { id: 'bar:2', type: 'bar', bar: { status: 'not_migrated_2' } }, - // ]; - dataArchive: Path.join(__dirname, '..', 'archives', '7.13.0_5k_so_node_01.zip'), - }, - { - name: 'node-02', - dataArchive: Path.join(__dirname, '..', 'archives', '7.13.0_5k_so_node_02.zip'), - }, - ], + if (getFips() === 0) { + it('migrates saved objects normally with multiple ES nodes', async () => { + const { startES } = createTestServers({ + adjustTimeout: (t: number) => jest.setTimeout(t), + settings: { + es: { + license: 'basic', + clusterName: 'es-test-cluster', + nodes: [ + { + name: 'node-01', + // original SO (5000 total; 2500 of type `foo` + 2500 of type `bar`): + // [ + // { id: 'foo:1', type: 'foo', foo: { status: 'not_migrated_1' } }, + // { id: 'bar:1', type: 'bar', bar: { status: 'not_migrated_1' } }, + // { id: 'foo:2', type: 'foo', foo: { status: 'not_migrated_2' } }, + // { id: 'bar:2', type: 'bar', bar: { status: 'not_migrated_2' } }, + // ]; + dataArchive: Path.join(__dirname, '..', 'archives', '7.13.0_5k_so_node_01.zip'), + }, + { + name: 'node-02', + dataArchive: Path.join(__dirname, '..', 'archives', '7.13.0_5k_so_node_02.zip'), + }, + ], + }, }, - }, - }); - - esServer = await startES(); - - root = createRoot({ - logFileName: Path.join(__dirname, `${LOG_FILE_PREFIX}.log`), - hosts: esServer.hosts, - }); - - await root.preboot(); - const setup = await root.setup(); - setup.savedObjects.registerType({ - name: 'foo', - hidden: false, - mappings: { properties: { status: { type: 'text' } } }, - namespaceType: 'agnostic', - migrations: { - '7.14.0': (doc) => { - if (doc.attributes?.status) { - doc.attributes.status = doc.attributes.status.replace('not_migrated', 'migrated'); - } - return doc; + }); + + esServer = await startES(); + + root = createRoot({ + logFileName: Path.join(__dirname, `${LOG_FILE_PREFIX}.log`), + hosts: esServer.hosts, + }); + + await root.preboot(); + const setup = await root.setup(); + setup.savedObjects.registerType({ + name: 'foo', + hidden: false, + mappings: { properties: { status: { type: 'text' } } }, + namespaceType: 'agnostic', + migrations: { + '7.14.0': (doc) => { + if (doc.attributes?.status) { + doc.attributes.status = doc.attributes.status.replace('not_migrated', 'migrated'); + } + return doc; + }, }, - }, - }); - setup.savedObjects.registerType({ - name: 'bar', - hidden: false, - mappings: { properties: { status: { type: 'text' } } }, - namespaceType: 'agnostic', - migrations: { - '7.14.0': (doc) => { - if (doc.attributes?.status) { - doc.attributes.status = doc.attributes.status.replace('not_migrated', 'migrated'); - } - return doc; + }); + setup.savedObjects.registerType({ + name: 'bar', + hidden: false, + mappings: { properties: { status: { type: 'text' } } }, + namespaceType: 'agnostic', + migrations: { + '7.14.0': (doc) => { + if (doc.attributes?.status) { + doc.attributes.status = doc.attributes.status.replace('not_migrated', 'migrated'); + } + return doc; + }, }, - }, + }); + + await root.start(); + const esClient = esServer.es.getClient(); + + const migratedFooDocs = await fetchDocs(esClient, migratedIndexAlias, 'foo'); + expect(migratedFooDocs.length).toBe(2500); + migratedFooDocs.forEach((doc, i) => { + expect(doc.id).toBe(`foo:${i}`); + expect(doc.foo.status).toBe(`migrated_${i}`); + expect(doc.typeMigrationVersion).toBe('7.14.0'); + }); + + const migratedBarDocs = await fetchDocs(esClient, migratedIndexAlias, 'bar'); + expect(migratedBarDocs.length).toBe(2500); + migratedBarDocs.forEach((doc, i) => { + expect(doc.id).toBe(`bar:${i}`); + expect(doc.bar.status).toBe(`migrated_${i}`); + expect(doc.typeMigrationVersion).toBe('7.14.0'); + }); }); - - await root.start(); - const esClient = esServer.es.getClient(); - - const migratedFooDocs = await fetchDocs(esClient, migratedIndexAlias, 'foo'); - expect(migratedFooDocs.length).toBe(2500); - migratedFooDocs.forEach((doc, i) => { - expect(doc.id).toBe(`foo:${i}`); - expect(doc.foo.status).toBe(`migrated_${i}`); - expect(doc.typeMigrationVersion).toBe('7.14.0'); - }); - - const migratedBarDocs = await fetchDocs(esClient, migratedIndexAlias, 'bar'); - expect(migratedBarDocs.length).toBe(2500); - migratedBarDocs.forEach((doc, i) => { - expect(doc.id).toBe(`bar:${i}`); - expect(doc.bar.status).toBe(`migrated_${i}`); - expect(doc.typeMigrationVersion).toBe('7.14.0'); + } else { + it('skips the test when running in FIPS mode since the data archives cause the es nodes to run with a basic license', () => { + expect(getFips()).toBe(1); }); - }); + } }); diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/read_batch_size.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/read_batch_size.test.ts index df809d8c4c173..9f970ed234d71 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/read_batch_size.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/read_batch_size.test.ts @@ -15,6 +15,7 @@ import { } from '@kbn/core-test-helpers-kbn-server'; import { clearLog, readLog, startElasticsearch } from '../kibana_migrator_test_kit'; import { delay } from '../test_utils'; +import { getFips } from 'crypto'; const logFilePath = join(__dirname, 'read_batch_size.log'); @@ -36,33 +37,39 @@ describe('migration v2 - read batch size', () => { await delay(5); // give it a few seconds... cause we always do ¯\_(ツ)_/¯ }); - it('reduces the read batchSize in half if a batch exceeds maxReadBatchSizeBytes', async () => { - root = createRoot({ maxReadBatchSizeBytes: 15000 }); - await root.preboot(); - await root.setup(); - await root.start(); + if (getFips() === 0) { + it('reduces the read batchSize in half if a batch exceeds maxReadBatchSizeBytes', async () => { + root = createRoot({ maxReadBatchSizeBytes: 15000 }); + await root.preboot(); + await root.setup(); + await root.start(); - // Check for migration steps present in the logs - logs = await readLog(logFilePath); + // Check for migration steps present in the logs + logs = await readLog(logFilePath); - expect(logs).toMatch( - /Read a batch with a response content length of \d+ bytes which exceeds migrations\.maxReadBatchSizeBytes, retrying by reducing the batch size in half to 15/ - ); - expect(logs).toMatch('[.kibana] Migration completed'); - }); + expect(logs).toMatch( + /Read a batch with a response content length of \d+ bytes which exceeds migrations\.maxReadBatchSizeBytes, retrying by reducing the batch size in half to 15/ + ); + expect(logs).toMatch('[.kibana] Migration completed'); + }); - it('does not reduce the read batchSize in half if no batches exceeded maxReadBatchSizeBytes', async () => { - root = createRoot({ maxReadBatchSizeBytes: 50000 }); - await root.preboot(); - await root.setup(); - await root.start(); + it('does not reduce the read batchSize in half if no batches exceeded maxReadBatchSizeBytes', async () => { + root = createRoot({ maxReadBatchSizeBytes: 50000 }); + await root.preboot(); + await root.setup(); + await root.start(); - // Check for migration steps present in the logs - logs = await readLog(logFilePath); + // Check for migration steps present in the logs + logs = await readLog(logFilePath); - expect(logs).not.toMatch('retrying by reducing the batch size in half to'); - expect(logs).toMatch('[.kibana] Migration completed'); - }); + expect(logs).not.toMatch('retrying by reducing the batch size in half to'); + expect(logs).toMatch('[.kibana] Migration completed'); + }); + } else { + it('cannot run tests with dataArchives that have a basic licesne in FIPS mode', () => { + expect(getFips()).toBe(1); + }); + } }); function createRoot({ maxReadBatchSizeBytes }: { maxReadBatchSizeBytes?: number }) { diff --git a/src/core/server/integration_tests/saved_objects/serverless/migrations/smoke.test.ts b/src/core/server/integration_tests/saved_objects/serverless/migrations/smoke.test.ts index e76bbd8d2d65b..27af749593e70 100644 --- a/src/core/server/integration_tests/saved_objects/serverless/migrations/smoke.test.ts +++ b/src/core/server/integration_tests/saved_objects/serverless/migrations/smoke.test.ts @@ -13,28 +13,35 @@ import { TestServerlessKibanaUtils, createTestServerlessInstances, } from '@kbn/core-test-helpers-kbn-server'; +import { getFips } from 'crypto'; -describe('Basic smoke test', () => { +describe('Basic smoke test', function () { let serverlessES: TestServerlessESUtils; let serverlessKibana: TestServerlessKibanaUtils; let root: TestServerlessKibanaUtils['root']; - beforeEach(async () => { - const { startES, startKibana } = createTestServerlessInstances({ - adjustTimeout: jest.setTimeout, + if (getFips() === 0) { + beforeEach(async () => { + const { startES, startKibana } = createTestServerlessInstances({ + adjustTimeout: jest.setTimeout, + }); + serverlessES = await startES(); + serverlessKibana = await startKibana(); + root = serverlessKibana.root; }); - serverlessES = await startES(); - serverlessKibana = await startKibana(); - root = serverlessKibana.root; - }); - afterEach(async () => { - await serverlessES?.stop(); - await serverlessKibana?.stop(); - }); + afterEach(async () => { + await serverlessES?.stop(); + await serverlessKibana?.stop(); + }); - test('it can start Kibana running against serverless ES', async () => { - const { body } = await request.get(root, '/api/status').expect(200); - expect(body).toMatchObject({ status: { overall: { level: 'available' } } }); - }); + test('it can start Kibana running against serverless ES', async () => { + const { body } = await request.get(root, '/api/status').expect(200); + expect(body).toMatchObject({ status: { overall: { level: 'available' } } }); + }); + } else { + test('FIPS is enabled, serverless doesnt like the config overrides', () => { + expect(getFips()).toBe(1); + }); + } }); diff --git a/src/dev/build/lib/integration_tests/fs.test.ts b/src/dev/build/lib/integration_tests/fs.test.ts index 2b1adac411f65..4a24da0e0b5f6 100644 --- a/src/dev/build/lib/integration_tests/fs.test.ts +++ b/src/dev/build/lib/integration_tests/fs.test.ts @@ -13,6 +13,7 @@ import { chmodSync, statSync } from 'fs'; import del from 'del'; import { mkdirp, write, read, getChildPaths, copyAll, getFileHash, untar, gunzip } from '../fs'; +import { getFips } from 'crypto'; const TMP = resolve(__dirname, '../__tmp__'); const FIXTURES = resolve(__dirname, '../__fixtures__'); @@ -266,9 +267,12 @@ describe('getFileHash()', () => { '7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730' ); }); - it('resolves with the md5 hash of a file', async () => { - expect(await getFileHash(BAR_TXT_PATH, 'md5')).toBe('c157a79031e1c40f85931829bc5fc552'); - }); + + if (getFips() !== 1) { + it('resolves with the md5 hash of a file', async () => { + expect(await getFileHash(BAR_TXT_PATH, 'md5')).toBe('c157a79031e1c40f85931829bc5fc552'); + }); + } }); describe('untar()', () => { diff --git a/src/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts b/src/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts index afbae27ec367d..ab440e60629b5 100644 --- a/src/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts +++ b/src/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts @@ -27,10 +27,13 @@ describe('Elasticsearch blob storage', () => { beforeAll(async () => { ElasticsearchBlobStorageClient.configureConcurrentTransfers(Infinity); - const { startES, startKibana } = createTestServers({ adjustTimeout: jest.setTimeout }); + + const { startES, startKibana } = createTestServers({ + adjustTimeout: jest.setTimeout, + }); manageES = await startES(); manageKbn = await startKibana(); - esClient = manageKbn.coreStart.elasticsearch.client.asInternalUser; + esClient = manageKbn.coreStart.elasticsearch.createClient('es.test').asInternalUser; }); afterAll(async () => { diff --git a/src/plugins/files/server/file_client/create_es_file_client.ts b/src/plugins/files/server/file_client/create_es_file_client.ts index ddfcfc0833e80..3302e878c3631 100644 --- a/src/plugins/files/server/file_client/create_es_file_client.ts +++ b/src/plugins/files/server/file_client/create_es_file_client.ts @@ -8,6 +8,7 @@ */ import type { Logger, ElasticsearchClient } from '@kbn/core/server'; +import { getFips } from 'crypto'; import { ElasticsearchBlobStorageClient } from '../blob_storage_service'; import { FileClientImpl } from './file_client'; import type { FileClient } from './types'; @@ -66,12 +67,18 @@ export function createEsFileClient(arg: CreateEsFileClientArgs): FileClient { maxSizeBytes, indexIsAlias, } = arg; + + let hashes: Array<'sha1' | 'sha256' | 'sha512' | 'md5'> = ['sha1', 'sha256', 'sha512']; + if (getFips() !== 1) { + hashes = ['md5', ...hashes]; + } + return new FileClientImpl( { id: NO_FILE_KIND, http: {}, maxSizeBytes, - hashes: ['md5', 'sha1', 'sha256', 'sha512'], + hashes, }, new EsIndexFilesMetadataClient(metadataIndex, elasticsearchClient, logger, indexIsAlias), new ElasticsearchBlobStorageClient( diff --git a/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts b/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts index 3492db16ee1a9..16fd2e535763b 100644 --- a/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts +++ b/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts @@ -13,6 +13,7 @@ import { TestEnvironmentUtils, setupIntegrationEnvironment } from '../../test_ut import { createEsFileClient } from '../create_es_file_client'; import { FileClient } from '../types'; import { FileMetadata } from '../../../common'; +import { getFips } from 'crypto'; describe('ES-index-backed file client', () => { let esClient: TestEnvironmentUtils['esClient']; @@ -107,13 +108,21 @@ describe('ES-index-backed file client', () => { }); await file.uploadContent(Readable.from([Buffer.from('test')])); - expect(file.toJSON().hash).toStrictEqual({ - md5: '098f6bcd4621d373cade4e832627b4f6', + let expected: Record = { sha1: 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3', sha256: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', sha512: 'ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff', - }); + }; + + if (getFips() !== 1) { + expected = { + md5: '098f6bcd4621d373cade4e832627b4f6', + ...expected, + }; + } + + expect(file.toJSON().hash).toStrictEqual(expected); await deleteFile({ id: file.id, hasContent: true }); }); diff --git a/src/plugins/files/server/file_client/stream_transforms/file_hash_transform/file_hash_transform.test.ts b/src/plugins/files/server/file_client/stream_transforms/file_hash_transform/file_hash_transform.test.ts index f0801cf763dd0..18f0cd6184e71 100644 --- a/src/plugins/files/server/file_client/stream_transforms/file_hash_transform/file_hash_transform.test.ts +++ b/src/plugins/files/server/file_client/stream_transforms/file_hash_transform/file_hash_transform.test.ts @@ -24,6 +24,8 @@ import { BlobStorageService } from '../../../blob_storage_service'; import { InternalFileShareService } from '../../../file_share_service'; import { InternalFileService } from '../../../file_service/internal_file_service'; +import { getFips } from 'crypto'; + describe('When using the FileHashTransform', () => { let file: IFile; let fileContent: Readable; @@ -75,23 +77,25 @@ describe('When using the FileHashTransform', () => { expect(() => fileHash.getFileHash()).toThrow('File hash generation not yet complete'); }); - it.each([ - ['md5', '098f6bcd4621d373cade4e832627b4f6'], - ['sha1', 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'], - ['sha256', '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'], - [ - 'sha512', - 'ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff', - ], - ] as Array<[SupportedFileHashAlgorithm, string]>)( - 'should generate file hash using algorithm: %s', - async (algorithm, expectedHash) => { - const fileHash = createFileHashTransform(algorithm); - await file.uploadContent(fileContent, undefined, { - transforms: [fileHash], - }); + describe('algorithms', function () { + it.each([ + ...(getFips() !== 1 ? [['md5', '098f6bcd4621d373cade4e832627b4f6']] : []), + ['sha1', 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'], + ['sha256', '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'], + [ + 'sha512', + 'ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff', + ], + ] as Array<[SupportedFileHashAlgorithm, string]>)( + 'should generate file hash using algorithm: %s', + async (algorithm, expectedHash) => { + const fileHash = createFileHashTransform(algorithm); + await file.uploadContent(fileContent, undefined, { + transforms: [fileHash], + }); - expect(fileHash.getFileHash()).toEqual({ algorithm, value: expectedHash }); - } - ); + expect(fileHash.getFileHash()).toEqual({ algorithm, value: expectedHash }); + } + ); + }); }); diff --git a/test/functional/apps/dashboard/group5/dashboard_panel_listing.ts b/test/functional/apps/dashboard/group5/dashboard_panel_listing.ts index 1685228699fc3..abd6b1c5dd1c1 100644 --- a/test/functional/apps/dashboard/group5/dashboard_panel_listing.ts +++ b/test/functional/apps/dashboard/group5/dashboard_panel_listing.ts @@ -17,7 +17,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const dashboardAddPanel = getService('dashboardAddPanel'); - describe('dashboard panel listing', () => { + describe('dashboard panel listing', function () { + this.tags('skipFIPS'); before(async () => { await kibanaServer.savedObjects.cleanStandardList(); await kibanaServer.importExport.load( diff --git a/test/server_integration/http/ssl_with_p12/index.js b/test/server_integration/http/ssl_with_p12/index.js index b402ce548c6a1..21c09a8d7e63f 100644 --- a/test/server_integration/http/ssl_with_p12/index.js +++ b/test/server_integration/http/ssl_with_p12/index.js @@ -10,7 +10,8 @@ export default function ({ getService }) { const supertest = getService('supertest'); - describe('kibana server with ssl', () => { + describe('kibana server with ssl', function () { + this.tags('skipFIPS'); it('handles requests using ssl with a P12 keystore', async () => { await supertest.get('/').expect(302); }); diff --git a/test/server_integration/http/ssl_with_p12_intermediate/index.js b/test/server_integration/http/ssl_with_p12_intermediate/index.js index b01df762c7345..0fc4a2f793e20 100644 --- a/test/server_integration/http/ssl_with_p12_intermediate/index.js +++ b/test/server_integration/http/ssl_with_p12_intermediate/index.js @@ -10,7 +10,8 @@ export default function ({ getService }) { const supertest = getService('supertest'); - describe('kibana server with ssl', () => { + describe('kibana server with ssl', function () { + this.tags('skipFIPS'); it('handles requests using ssl with a P12 keystore that uses an intermediate CA', async () => { await supertest.get('/').expect(302); }); diff --git a/x-pack/plugins/actions/server/integration_tests/axios_utils_connection.test.ts b/x-pack/plugins/actions/server/integration_tests/axios_utils_connection.test.ts index a0454cb2bbc18..99559e8ce6b68 100644 --- a/x-pack/plugins/actions/server/integration_tests/axios_utils_connection.test.ts +++ b/x-pack/plugins/actions/server/integration_tests/axios_utils_connection.test.ts @@ -28,6 +28,7 @@ import { DEFAULT_MICROSOFT_GRAPH_API_SCOPE, DEFAULT_MICROSOFT_GRAPH_API_URL, } from '../../common'; +import { getFips } from 'crypto'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -251,19 +252,6 @@ describe('axios connections', () => { expect(res.status).toBe(200); }); - test('it works with pfx and passphrase in SSL overrides', async () => { - const { url, server } = await createServer({ useHttps: true, requestCert: true }); - testServer = server; - - const configurationUtilities = getACUfromConfig(); - const sslOverrides = { - pfx: KIBANA_P12, - passphrase: 'storepass', - }; - const res = await request({ axios, url, logger, configurationUtilities, sslOverrides }); - expect(res.status).toBe(200); - }); - test('it fails with cert and key but no ca in SSL overrides', async () => { const { url, server } = await createServer({ useHttps: true, requestCert: true }); testServer = server; @@ -278,18 +266,33 @@ describe('axios connections', () => { await expect(fn()).rejects.toThrow('certificate'); }); - test('it fails with pfx but no passphrase in SSL overrides', async () => { - const { url, server } = await createServer({ useHttps: true, requestCert: true }); - testServer = server; + if (getFips() !== 1) { + test('it works with pfx and passphrase in SSL overrides', async () => { + const { url, server } = await createServer({ useHttps: true, requestCert: true }); + testServer = server; + + const configurationUtilities = getACUfromConfig(); + const sslOverrides = { + pfx: KIBANA_P12, + passphrase: 'storepass', + }; + const res = await request({ axios, url, logger, configurationUtilities, sslOverrides }); + expect(res.status).toBe(200); + }); - const configurationUtilities = getACUfromConfig(); - const sslOverrides = { - pfx: KIBANA_P12, - }; - const fn = async () => - await request({ axios, url, logger, configurationUtilities, sslOverrides }); - await expect(fn()).rejects.toThrow('mac verify'); - }); + test('it fails with pfx but no passphrase in SSL overrides', async () => { + const { url, server } = await createServer({ useHttps: true, requestCert: true }); + testServer = server; + + const configurationUtilities = getACUfromConfig(); + const sslOverrides = { + pfx: KIBANA_P12, + }; + const fn = async () => + await request({ axios, url, logger, configurationUtilities, sslOverrides }); + await expect(fn()).rejects.toThrow('mac verify'); + }); + } test('it fails with a client-side certificate issued by an invalid ca', async () => { const { url, server } = await createServer({ useHttps: true, requestCert: true }); diff --git a/x-pack/plugins/fleet/.storybook/smoke.test.tsx b/x-pack/plugins/fleet/.storybook/smoke.test.tsx index a3984a42a5ab2..63c1199b75aa9 100644 --- a/x-pack/plugins/fleet/.storybook/smoke.test.tsx +++ b/x-pack/plugins/fleet/.storybook/smoke.test.tsx @@ -5,22 +5,30 @@ * 2.0. */ +import { getFips } from 'crypto'; + import { mount } from 'enzyme'; import { createElement } from 'react'; import { act } from 'react-dom/test-utils'; import initStoryshots from '@storybook/addon-storyshots'; -describe('Fleet Storybook Smoke', () => { - test('Init', async () => { - await initStoryshots({ - configPath: __dirname, - framework: 'react', - test: async ({ story }) => { - const renderer = mount(createElement(story.render)); - // wait until the element will perform all renders and resolve all promises (lazy loading, especially) - await act(() => new Promise((resolve) => setTimeout(resolve, 0))); - expect(renderer.html()).not.toContain('euiErrorBoundary'); - }, +describe('Fleet Storybook Smoke', function () { + if (getFips() !== 1) { + test('Init', async () => { + await initStoryshots({ + configPath: __dirname, + framework: 'react', + test: async ({ story }) => { + const renderer = mount(createElement(story.render)); + // wait until the element will perform all renders and resolve all promises (lazy loading, especially) + await act(() => new Promise((resolve) => setTimeout(resolve, 0))); + expect(renderer.html()).not.toContain('euiErrorBoundary'); + }, + }); + }); + } else { + test('fips is enabled', function () { + expect(getFips() === 1).toEqual(true); }); - }); + } }); diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts index 9d71e15958480..714b16af5bcd2 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts @@ -152,7 +152,6 @@ export async function hashSecret(secret: string) { return `${salt}:${derivedKey.toString('hex')}`; } - async function verifySecret(hash: string, secret: string) { const [salt, key] = hash.split(':'); const derivedKey = await pbkdf2Async(secret, salt, maxIteration, keyLength, 'sha512'); diff --git a/x-pack/test/functional/apps/index_lifecycle_management/read_only_view.ts b/x-pack/test/functional/apps/index_lifecycle_management/read_only_view.ts index 030074a97b4bd..b30ee9ecee763 100644 --- a/x-pack/test/functional/apps/index_lifecycle_management/read_only_view.ts +++ b/x-pack/test/functional/apps/index_lifecycle_management/read_only_view.ts @@ -15,6 +15,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const security = getService('security'); describe('Read only view', function () { + this.tags('skipFIPS'); before(async () => { await security.testUser.setRoles(['read_ilm']);