Skip to content

Commit 6250eac

Browse files
Add option to disable cqlsh history
We can disable saving of the history either via command-line parameter --disable-history, or by setting disabled = True in the history section of the cqlshrc. Both options will read existing history, and just won't save new commands. Update help and docs for cqlsh history. Add startup info logline whenr history logging is enabled. Add a fix for cqlshrc file path not correctly expanding. patch by Ekaterina Dimitrova; reviewed by Mick Semb Wever for CASSANDRA-XXX Co-authored-by: Alex Ott alex.ott@datastax.com Co-authored-by: Jaroslaw Grabowski jaroslaw.grabowski@datastax.com
1 parent 7532be5 commit 6250eac

File tree

3 files changed

+52
-9
lines changed

3 files changed

+52
-9
lines changed

conf/cqlshrc.sample

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ port = 9042
104104
; max_trace_wait = 10.0
105105

106106

107+
[history]
108+
;; Controls whether command history is saved to ~/.cassandra/cqlsh_history
109+
;; When disabled, existing history will still be loaded but new commands
110+
;; will not be saved. This can be useful for security purposes to prevent
111+
;; sensitive commands (e.g., those containing passwords) from being persisted.
112+
;; This can also be controlled via the --disable-history command line option.
113+
; disabled = false
114+
115+
107116
;[ssl]
108117
; certfile = ~/keys/cassandra.cert
109118

doc/modules/cassandra/pages/managing/tools/cqlsh.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ Example config values and documentation can be found in the
5757
[[cql_history]]
5858
== cql history
5959

60-
All CQL commands you execute are written to a history file. By default, CQL history will be written to `~/.cassandra/cql_history`. You can change this default by setting the environment variable `CQL_HISTORY` like `~/some/other/path/to/cqlsh_history` where `cqlsh_history` is a file. All parent directories to history file will be created if they do not exist. If you do not want to persist history, you can do so by setting CQL_HISTORY to /dev/null.
61-
This feature is supported from Cassandra 4.1.
60+
All CQL commands you execute are written to a history file. By default, CQL history will be written to `~/.cassandra/cql_history`.
61+
You can change this default by setting the environment variable `CQL_HISTORY` like `~/some/other/path/to/cqlsh_history` where `cqlsh_history` is a file. All parent directories to history file will be created if they do not exist. If you do not want to persist history, you can do so by setting CQL_HISTORY to `/dev/null`. This can also be controlled via the --disable-history command line option or from the cqlshrc file. Disabling history is supported since Cassandra 4.0.
6262

6363
== Command Line Options
6464

pylib/cqlshlib/cqlshmain.py

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import sys
2626
import time
2727
import traceback
28+
from typing import Any
2829
import warnings
2930
import webbrowser
3031
from contextlib import contextmanager
@@ -93,7 +94,6 @@
9394

9495
# BEGIN history config
9596

96-
9797
def mkdirp(path):
9898
"""Creates all parent directories up to path parameter or fails when path exists, but it is not a directory."""
9999

@@ -120,6 +120,16 @@ def resolve_cql_history_file():
120120
except OSError:
121121
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)
122122

123+
OLD_HISTORY = os.path.expanduser(os.path.join('~', '.cqlsh_history'))
124+
if os.path.exists(OLD_HISTORY):
125+
if os.path.exists(HISTORY):
126+
print('\nWarning: .cqlsh_history files were found at both the old location ({0})'
127+
+ ' and the new location ({1}), the old file will not be migrated to the new'
128+
+ ' location, and the new location will be used for now. You should manually'
129+
+ ' consolidate these files at the new location, and remove the old file.'
130+
.format(OLD_HISTORY, HISTORY))
131+
else:
132+
os.rename(OLD_HISTORY, HISTORY)
123133

124134
# END history config
125135

@@ -272,7 +282,8 @@ def __init__(self, hostname, port, config_file, color=False,
272282
protocol_version=None,
273283
connect_timeout=DEFAULT_CONNECT_TIMEOUT_SECONDS,
274284
is_subshell=False,
275-
auth_provider=None):
285+
auth_provider=None,
286+
disable_history=False):
276287
cmd.Cmd.__init__(self, completekey=completekey)
277288
self.hostname = hostname
278289
self.port = port
@@ -357,6 +368,14 @@ def __init__(self, hostname, port, config_file, color=False,
357368
self.reset_prompt()
358369
self.report_connection()
359370
print('Use HELP for help.')
371+
# Inform users about history logging if not disabled
372+
if not disable_history and readline is not None:
373+
print()
374+
print("ATTENTION: All commands will be saved to history file: %s" % HISTORY)
375+
print("This may include sensitive information such as passwords.")
376+
print("To disable history, use --disable-history or set 'disabled = true' in the [history] section of cqlshrc.")
377+
print("See https://cassandra.apache.org/doc/latest/tools/cqlsh.html for more information.")
378+
print()
360379
else:
361380
self.show_line_nums = True
362381
self.stdin = stdin
@@ -1896,8 +1915,8 @@ def init_history(self):
18961915
delims += '.'
18971916
readline.set_completer_delims(delims)
18981917

1899-
def save_history(self):
1900-
if readline is not None:
1918+
def save_history(self, history_disabled=False):
1919+
if readline is not None and not history_disabled:
19011920
try:
19021921
readline.write_history_file(HISTORY)
19031922
except IOError:
@@ -2037,7 +2056,7 @@ def read_options(cmdlineargs, parser, config_file, cql_dir, environment=os.envir
20372056
argvalues.request_timeout = option_with_default(configs.getint, 'connection', 'request_timeout', Shell.DEFAULT_REQUEST_TIMEOUT_SECONDS)
20382057
argvalues.execute = None
20392058
argvalues.insecure_password_without_warning = False
2040-
2059+
argvalues.disable_history = option_with_default(configs.getboolean, 'history', 'disabled', False)
20412060
options, arguments = parser.parse_known_args(cmdlineargs, argvalues)
20422061

20432062
# Credentials from cqlshrc will be expanded,
@@ -2208,6 +2227,8 @@ def main(cmdline, pkgpath):
22082227
help='Specify the default request timeout in seconds (default: %(default)s seconds).')
22092228
parser.add_argument("-t", "--tty", action='store_true', dest='tty',
22102229
help='Force tty mode (command prompt).')
2230+
parser.add_argument('--disable-history', default=False, action='store_true',
2231+
help='Disable saving of history (existing history will still be loaded)')
22112232

22122233
# This is a hidden option to suppress the warning when the -p/--password command line option is used.
22132234
# 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.
@@ -2233,6 +2254,18 @@ def main(cmdline, pkgpath):
22332254
config_file = default_cqlshrc
22342255

22352256
cql_dir = os.path.dirname(config_file)
2257+
2258+
old_config_file = os.path.expanduser(os.path.join('~', '.cqlshrc'))
2259+
if os.path.exists(old_config_file):
2260+
if os.path.exists(config_file):
2261+
print('\nWarning: cqlshrc config files were found at both the old location ({0})'
2262+
+ ' and the new location ({1}), the old config file will not be migrated to the new'
2263+
+ ' location, and the new location will be used for now. You should manually'
2264+
+ ' consolidate the config files at the new location and remove the old file.'
2265+
.format(old_config_file, config_file))
2266+
else:
2267+
os.rename(old_config_file, config_file)
2268+
22362269
(options, hostname, port) = read_options(cmdline, parser, config_file, cql_dir)
22372270

22382271
docspath = get_docspath(pkgpath)
@@ -2332,7 +2365,8 @@ def main(cmdline, pkgpath):
23322365
config_file=config_file,
23332366
cred_file=options.credentials,
23342367
username=options.username,
2335-
password=options.password))
2368+
password=options.password),
2369+
disable_history=options.disable_history)
23362370
except KeyboardInterrupt:
23372371
sys.exit('Connection aborted.')
23382372
except CQL_ERRORS as e:
@@ -2353,7 +2387,7 @@ def handle_sighup():
23532387

23542388
shell.init_history()
23552389
shell.cmdloop()
2356-
shell.save_history()
2390+
shell.save_history(options.disable_history)
23572391

23582392
if shell.batch_mode and shell.statement_error:
23592393
sys.exit(2)

0 commit comments

Comments
 (0)