This is an automated email from the ASF dual-hosted git repository.

mck pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit ee273af1d64f9f9c54d0cb4c9d38598b83bc3bbd
Merge: cd9d6daa9e be0b73ecba
Author: mck <[email protected]>
AuthorDate: Tue Mar 17 23:08:39 2026 +0100

    Merge branch 'cassandra-5.0' into trunk
    
    * cassandra-5.0:
      Add option to disable cqlsh history

 CHANGES.txt                                        |  1 +
 conf/cqlshrc.sample                                |  9 +++++
 .../cassandra/pages/managing/tools/cqlsh.adoc      |  4 +-
 pylib/cqlshlib/cqlshmain.py                        | 47 +++++++++++++++++++---
 4 files changed, 53 insertions(+), 8 deletions(-)

diff --cc conf/cqlshrc.sample
index c396edfed9,79d719460e..3c957a79a2
--- a/conf/cqlshrc.sample
+++ b/conf/cqlshrc.sample
@@@ -104,6 -110,17 +104,15 @@@ port = 904
  ; max_trace_wait = 10.0
  
  
 -
+ [history]
+ ;; Controls whether command history is saved to ~/.cassandra/cqlsh_history
+ ;; When disabled, existing history will still be loaded but new commands
+ ;; will not be saved. This can be useful for security purposes to prevent
+ ;; sensitive commands (e.g., those containing passwords) from being persisted.
+ ;; This can also be controlled via the --disable-history command line option.
+ ; disabled = false
+ 
+ 
 -
  ;[ssl]
  ; certfile = ~/keys/cassandra.cert
  
diff --cc pylib/cqlshlib/cqlshmain.py
index 8b26e33078,5c97fa3f74..c13256dd40
--- a/pylib/cqlshlib/cqlshmain.py
+++ b/pylib/cqlshlib/cqlshmain.py
@@@ -23,8 -24,7 +23,9 @@@ import o
  import re
  import subprocess
  import sys
 +import time
  import traceback
++from typing import Any
  import warnings
  import webbrowser
  from contextlib import contextmanager
@@@ -120,8 -193,35 +121,18 @@@ try
  except OSError:
      print('\nWarning: Cannot create directory at `%s`. Command history will 
not be saved. Please check what was the environment property CQL_HISTORY set 
to.\n' % HISTORY_DIR)
  
 -# END history config
 -
 -DEFAULT_CQLSHRC = os.path.expanduser(os.path.join('~', '.cassandra', 
'cqlshrc'))
 -
 -if cfarguments.cqlshrc is not None:
 -    CONFIG_FILE = os.path.expanduser(cfarguments.cqlshrc)
 -    if not os.path.exists(CONFIG_FILE):
 -        print('\nWarning: Specified cqlshrc location `%s` does not exist.  
Using `%s` instead.\n' % (CONFIG_FILE, DEFAULT_CQLSHRC))
 -        CONFIG_FILE = DEFAULT_CQLSHRC
 -else:
 -    CONFIG_FILE = DEFAULT_CQLSHRC
 -
 -CQL_DIR = os.path.dirname(CONFIG_FILE)
 -
 -OLD_CONFIG_FILE = os.path.expanduser(os.path.join('~', '.cqlshrc'))
 -if os.path.exists(OLD_CONFIG_FILE):
 -    if os.path.exists(CONFIG_FILE):
 -        print('\nWarning: cqlshrc config files were found at both the old 
location ({0})'
 -              + ' and the new location ({1}), the old config file will not be 
migrated to the new'
 -              + ' location, and the new location will be used for now.  You 
should manually'
 -              + ' consolidate the config files at the new location and remove 
the old file.'
 -              .format(OLD_CONFIG_FILE, CONFIG_FILE))
 -    else:
 -        os.rename(OLD_CONFIG_FILE, CONFIG_FILE)
+ OLD_HISTORY = os.path.expanduser(os.path.join('~', '.cqlsh_history'))
+ if os.path.exists(OLD_HISTORY):
 -    os.rename(OLD_HISTORY, HISTORY)
++    if os.path.exists(HISTORY):
++        print('\nWarning: .cqlsh_history files were found at both the old 
location ({0})'
++              + ' and the new location ({1}), the old file will not be 
migrated to the new'
++              + ' location, and the new location will be used for now.  You 
should manually'
++              + ' consolidate these files at the new location, and remove the 
old file.'
++              .format(OLD_HISTORY, HISTORY))
++    else:
++        os.rename(OLD_HISTORY, HISTORY)
  
 -# END history/config definition
 +# END history config
  
  CQL_ERRORS = (
      cassandra.AlreadyExists, cassandra.AuthenticationFailed, 
cassandra.CoordinationFailure,
@@@ -1896,8 -1969,11 +1916,8 @@@ class Shell(cmd.Cmd)
              delims += '.'
              readline.set_completer_delims(delims)
  
-     def save_history(self):
-         if readline is not None:
 -            # configure length of history shown
 -            self.max_history_length_shown = 50
 -
+     def save_history(self, history_disabled=False):
+         if readline is not None and not history_disabled:
              try:
                  readline.write_history_file(HISTORY)
              except IOError:
@@@ -2033,11 -2111,11 +2053,11 @@@ def read_options(cmdlineargs, parser, c
      argvalues.tty = option_with_default(configs.getboolean, 'ui', 'tty', 
sys.stdin.isatty())
      argvalues.protocol_version = option_with_default(configs.getint, 
'protocol', 'version', None)
      argvalues.cqlversion = option_with_default(configs.get, 'cql', 'version', 
None)
 -    argvalues.connect_timeout = option_with_default(configs.getint, 
'connection', 'timeout', DEFAULT_CONNECT_TIMEOUT_SECONDS)
 -    argvalues.request_timeout = option_with_default(configs.getint, 
'connection', 'request_timeout', DEFAULT_REQUEST_TIMEOUT_SECONDS)
 +    argvalues.connect_timeout = option_with_default(configs.getint, 
'connection', 'timeout', Shell.DEFAULT_CONNECT_TIMEOUT_SECONDS)
 +    argvalues.request_timeout = option_with_default(configs.getint, 
'connection', 'request_timeout', Shell.DEFAULT_REQUEST_TIMEOUT_SECONDS)
      argvalues.execute = None
      argvalues.insecure_password_without_warning = False
- 
+     argvalues.disable_history = option_with_default(configs.getboolean, 
'history', 'disabled', False)
      options, arguments = parser.parse_known_args(cmdlineargs, argvalues)
  
      # Credentials from cqlshrc will be expanded,
@@@ -2162,80 -2271,12 +2182,94 @@@ def insert_driver_hooks()
  
  def main(cmdline, pkgpath):
      insert_driver_hooks()
 -    (options, hostname, port) = read_options(cmdline)
  
 -    setup_docspath(pkgpath)
 -    setup_cqlruleset(options.cqlmodule)
 -    setup_cqldocs(options.cqlmodule)
 -    csv.field_size_limit(options.field_size_limit)
 +    epilog = f"Connects to {Shell.DEFAULT_HOST}:{Shell.DEFAULT_PORT}  by 
default. These \
 +    defaults can be changed by setting $CQLSH_HOST and/or $CQLSH_PORT. When a 
\
 +    host (and optional port number) are given on the command line, they take \
 +    precedence over any defaults."
 +
 +    description = "CQL Shell for Apache Cassandra"
 +
 +    parser = argparse.ArgumentParser(description=description, epilog=epilog,
 +                                     usage="Usage: %(prog)s [options] [host 
[port]]",
 +                                     prog='cqlsh')
 +    parser.add_argument('-v', '--version', action='version', version='cqlsh ' 
+ version)
 +    parser.add_argument("-C", "--color", action='store_true', dest='color',
 +                        help='Always use color output')
 +    parser.add_argument("--no-color", action='store_false', dest='color', 
help='Never use color output')
 +    parser.add_argument("--browser", dest='browser', help="""The browser to 
use to display CQL help, where BROWSER can be:
 +                                                        - one of the 
supported browsers in https://docs.python.org/3/library/webbrowser.html.
 +                                                        - browser path 
followed by %%s, example: /usr/bin/google-chrome-stable %%s""")
 +
 +    parser.add_argument('--ssl', action='store_true', help='Use SSL', 
default=False)
 +    parser.add_argument("-u", "--username", help="Authenticate as user.")
 +    parser.add_argument("-p", "--password", help="Authenticate using 
password.")
 +    parser.add_argument('-k', '--keyspace', help='Authenticate to the given 
keyspace.')
 +    parser.add_argument("-f", "--file", help="Execute commands from FILE, 
then exit")
 +    parser.add_argument('--debug', action='store_true',
 +                        help='Show additional debugging information')
 +    parser.add_argument('--coverage', action='store_true',
 +                        help='Collect coverage data')
 +    parser.add_argument("--encoding", help=f"Specify a non-default encoding 
for output."
 +                                           + " (Default: {UTF8)")
 +    parser.add_argument("--cqlshrc", help="Specify an alternative cqlshrc 
file location.")
 +    parser.add_argument("--credentials", help="Specify an alternative 
credentials file location.")
 +    parser.add_argument('--cqlversion', default=None,
 +                        help='Specify a particular CQL version, '
 +                             'by default the highest version supported by the 
server will be used.'
 +                             ' Examples: "3.0.3", "3.1.0"')
 +    parser.add_argument("--protocol-version", type=int, default=None,
 +                        help='Specify a specific protcol version otherwise 
the client will default and downgrade as necessary')
 +
 +    parser.add_argument("-e", "--execute", help='Execute the statement and 
quit.')
 +    parser.add_argument("--connect-timeout", 
default=Shell.DEFAULT_CONNECT_TIMEOUT_SECONDS, dest='connect_timeout',
 +                        help='Specify the connection timeout in seconds 
(default: %(default)s seconds).')
 +    parser.add_argument("--request-timeout", 
default=Shell.DEFAULT_REQUEST_TIMEOUT_SECONDS, dest='request_timeout',
 +                        help='Specify the default request timeout in seconds 
(default: %(default)s seconds).')
 +    parser.add_argument("-t", "--tty", action='store_true', dest='tty',
 +                        help='Force tty mode (command prompt).')
++    parser.add_argument('--disable-history', default=False, 
action='store_true',
++                        help='Disable saving of history (existing history 
will still be loaded)')
 +
 +    # This is a hidden option to suppress the warning when the -p/--password 
command line option is used.
 +    # Power users may use this option if they know no other people has access 
to the system where cqlsh is run or don't care about security.
 +    # Use of this option in scripting is discouraged. Please use a 
(temporary) credentials file where possible.
 +    # The Cassandra distributed tests (dtests) also use this option in some 
tests when a well-known password is supplied via the command line.
 +    parser.add_argument("--insecure-password-without-warning", 
action='store_true',
 +                        dest='insecure_password_without_warning',
 +                        help=argparse.SUPPRESS)
 +
 +    # use cfarguments for config file
 +
 +    cfarguments, args = parser.parse_known_args()
 +
 +    default_cqlshrc = os.path.expanduser(os.path.join('~', '.cassandra', 
'cqlshrc'))
 +
 +    if cfarguments.cqlshrc is not None:
 +        config_file = os.path.expanduser(cfarguments.cqlshrc)
 +        if not os.path.exists(config_file):
 +            print('\nWarning: Specified cqlshrc location `%s` does not exist. 
 Using `%s` instead.\n' %
 +                  (config_file, default_cqlshrc))
 +            config_file = default_cqlshrc
 +    else:
 +        config_file = default_cqlshrc
 +
 +    cql_dir = os.path.dirname(config_file)
++
++    old_config_file = os.path.expanduser(os.path.join('~', '.cqlshrc'))
++    if os.path.exists(old_config_file):
++        if os.path.exists(config_file):
++            print('\nWarning: cqlshrc config files were found at both the old 
location ({0})'
++                  + ' and the new location ({1}), the old config file will 
not be migrated to the new'
++                  + ' location, and the new location will be used for now.  
You should manually'
++                  + ' consolidate the config files at the new location and 
remove the old file.'
++                  .format(old_config_file, config_file))
++        else:
++            os.rename(old_config_file, config_file)
++
 +    (options, hostname, port) = read_options(cmdline, parser, config_file, 
cql_dir)
 +
 +    docspath = get_docspath(pkgpath)
  
      if options.file is None:
          stdin = None
@@@ -2329,10 -2368,11 +2363,11 @@@
                        connect_timeout=options.connect_timeout,
                        encoding=options.encoding,
                        auth_provider=authproviderhandling.load_auth_provider(
 -                          config_file=CONFIG_FILE,
 +                          config_file=config_file,
                            cred_file=options.credentials,
                            username=options.username,
-                           password=options.password))
+                           password=options.password),
+                       disable_history=options.disable_history)
      except KeyboardInterrupt:
          sys.exit('Connection aborted.')
      except CQL_ERRORS as e:


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to