diff --git a/packages/cli-repl/src/arg-parser.spec.ts b/packages/cli-repl/src/arg-parser.spec.ts index fa83121417..72bb532dd4 100644 --- a/packages/cli-repl/src/arg-parser.spec.ts +++ b/packages/cli-repl/src/arg-parser.spec.ts @@ -322,12 +322,12 @@ describe('arg-parser', () => { context('when providing --gssapiHostName', () => { const argv = [ ...baseArgv, uri, '--gssapiHostName', 'example.com' ]; - it('throws an error since it is not yet supported', () => { + it('throws an error since it is not supported', () => { try { parseCliArgs(argv); } catch (e: any) { expect(e).to.be.instanceOf(MongoshUnimplementedError); - expect(e.message).to.include('Argument --gssapiHostName is not yet supported in mongosh'); + expect(e.message).to.include('Argument --gssapiHostName is not supported in mongosh'); return; } expect.fail('Expected error'); @@ -488,15 +488,15 @@ describe('arg-parser', () => { }); }); - context('when providing --tlsFIPSMode', () => { - const argv = [ ...baseArgv, uri, '--tlsFIPSMode' ]; + context('when providing --sslFIPSMode', () => { + const argv = [ ...baseArgv, uri, '--sslFIPSMode' ]; - it('throws an error since it is not yet supported', () => { + it('throws an error since it is not supported', () => { try { parseCliArgs(argv); } catch (e: any) { expect(e).to.be.instanceOf(MongoshUnimplementedError); - expect(e.message).to.include('Argument --tlsFIPSMode is not yet supported in mongosh'); + expect(e.message).to.include('Argument --sslFIPSMode is not supported in mongosh'); return; } expect.fail('Expected error'); diff --git a/packages/cli-repl/src/arg-parser.ts b/packages/cli-repl/src/arg-parser.ts index af5791258a..7c2d81c6ae 100644 --- a/packages/cli-repl/src/arg-parser.ts +++ b/packages/cli-repl/src/arg-parser.ts @@ -115,7 +115,6 @@ const DEPRECATED_ARGS_WITH_REPLACEMENT: Record = { */ const UNSUPPORTED_ARGS: Readonly = [ 'sslFIPSMode', - 'tlsFIPSMode', 'gssapiHostName' ]; @@ -188,7 +187,7 @@ export function verifyCliArguments(args: any /* CliOptions */): string[] { for (const unsupported of UNSUPPORTED_ARGS) { if (unsupported in args) { throw new MongoshUnimplementedError( - `Argument --${unsupported} is not yet supported in mongosh`, + `Argument --${unsupported} is not supported in mongosh`, CommonErrors.InvalidArgument ); } diff --git a/packages/cli-repl/src/run.ts b/packages/cli-repl/src/run.ts index 30309b95f7..e2150a9aaa 100644 --- a/packages/cli-repl/src/run.ts +++ b/packages/cli-repl/src/run.ts @@ -1,3 +1,13 @@ +let fipsError: Error | undefined; +if (process.argv.includes('--tlsFIPSMode')) { + // FIPS mode should be enabled before we run any other code, including any dependencies. + try { + require('crypto').setFips(1); + } catch (err: any) { + fipsError = err; + } +} + import { CliRepl, parseCliArgs, runSmokeTests, USAGE, buildInfo } from './index'; import { getStoragePaths, getGlobalConfigPaths } from './config-directory'; import { getCSFLELibraryPaths } from './csfle-library-paths'; @@ -8,6 +18,7 @@ import { runMain } from 'module'; import readline from 'readline'; import askcharacter from 'askcharacter'; import stream from 'stream'; +import crypto from 'crypto'; // eslint-disable-next-line complexity, @typescript-eslint/no-floating-promises (async() => { @@ -29,6 +40,31 @@ import stream from 'stream'; const { version } = require('../package.json'); + if (options.tlsFIPSMode) { + if (!fipsError && !crypto.getFips()) { + // We can end up here if somebody used an unsual spelling of + // --tlsFIPSMode that our arg parser recognizes, but not the + // early check above, e.g. --tls-FIPS-mode. + // We should also just generally check that FIPS mode is + // actually enabled. + fipsError = new Error('FIPS mode not enabled despite requested'); + } + if (fipsError) { + // Adjust the error message depending on whether this mongosh binary + // potentially can support FIPS or not. + if (process.config.variables.node_shared_openssl) { + console.error('Could not enable FIPS mode. Please ensure that your system OpenSSL installation'); + console.error('supports FIPS, and see the mongosh FIPS documentation for more information.'); + } else { + console.error('Could not enable FIPS mode. This mongosh installation does not appear to'); + console.error('support FIPS. Please see the mongosh FIPS documentation for more information.'); + } + console.error('Error details:'); + console.error(fipsError); + process.exit(1); + } + } + if (options.help) { // eslint-disable-next-line no-console console.log(USAGE); diff --git a/packages/cli-repl/test/e2e.spec.ts b/packages/cli-repl/test/e2e.spec.ts index 6a1917d906..5e4b5fe04a 100644 --- a/packages/cli-repl/test/e2e.spec.ts +++ b/packages/cli-repl/test/e2e.spec.ts @@ -156,6 +156,20 @@ describe('e2e', function() { shell.assertContainsOutput('233'); }); }); + it('accepts a --tlsFIPSMode argument', async() => { + shell = TestShell.start({ + args: [ '--nodb', '--tlsFIPSMode' ] + }); + const result = await shell.waitForPromptOrExit(); + // Whether this worked depends on the environment the test is running in. + // We check both possibilities. + if (result.state === 'exit') { + shell.assertContainsOutput('Could not enable FIPS mode'); + expect(result.exitCode).to.equal(1); + } else { + expect(await shell.executeLine('[crypto.getFips()]')).to.include('[1]'); + } + }); }); describe('set db', () => {