Skip to content

Commit ee273af

Browse files
Merge branch 'cassandra-5.0' into trunk
* cassandra-5.0: Add option to disable cqlsh history
2 parents cd9d6da + be0b73e commit ee273af

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ Merged from 4.1:
322322
* Disk usage guardrail cannot be disabled when failure threshold is reached (CASSANDRA-21057)
323323
* ReadCommandController should close fast to avoid deadlock when building secondary index (CASSANDRA-19564)
324324
Merged from 4.0:
325+
* Add option to disable cqlsh history (CASSANDRA-21180)
325326
* Rate limit password changes (CASSANDRA-21202)
326327
* Node does not send multiple inflight echos (CASSANDRA-18866)
327328
* Obsolete expired SSTables before compaction starts (CASSANDRA-19776)

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 & 6 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
@@ -120,6 +121,16 @@ def resolve_cql_history_file():
120121
except OSError:
121122
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)
122123

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

124135
# END history config
125136

@@ -272,7 +283,8 @@ def __init__(self, hostname, port, config_file, color=False,
272283
protocol_version=None,
273284
connect_timeout=DEFAULT_CONNECT_TIMEOUT_SECONDS,
274285
is_subshell=False,
275-
auth_provider=None):
286+
auth_provider=None,
287+
disable_history=False):
276288
cmd.Cmd.__init__(self, completekey=completekey)
277289
self.hostname = hostname
278290
self.port = port
@@ -354,6 +366,14 @@ def __init__(self, hostname, port, config_file, color=False,
354366
self.check_build_versions()
355367

356368
if tty:
369+
# Inform users about history logging if not disabled
370+
if not disable_history and readline is not None:
371+
print()
372+
print("ATTENTION: All commands will be saved to history file: %s" % HISTORY)
373+
print("This may include sensitive information such as passwords.")
374+
print("To disable history, use --disable-history or set 'disabled = true' in the [history] section of cqlshrc.")
375+
print("See https://cassandra.apache.org/doc/latest/tools/cqlsh.html for more information.")
376+
print()
357377
self.reset_prompt()
358378
self.report_connection()
359379
print('Use HELP for help.')
@@ -1896,8 +1916,8 @@ def init_history(self):
18961916
delims += '.'
18971917
readline.set_completer_delims(delims)
18981918

1899-
def save_history(self):
1900-
if readline is not None:
1919+
def save_history(self, history_disabled=False):
1920+
if readline is not None and not history_disabled:
19011921
try:
19021922
readline.write_history_file(HISTORY)
19031923
except IOError:
@@ -2037,7 +2057,7 @@ def read_options(cmdlineargs, parser, config_file, cql_dir, environment=os.envir
20372057
argvalues.request_timeout = option_with_default(configs.getint, 'connection', 'request_timeout', Shell.DEFAULT_REQUEST_TIMEOUT_SECONDS)
20382058
argvalues.execute = None
20392059
argvalues.insecure_password_without_warning = False
2040-
2060+
argvalues.disable_history = option_with_default(configs.getboolean, 'history', 'disabled', False)
20412061
options, arguments = parser.parse_known_args(cmdlineargs, argvalues)
20422062

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

22122234
# This is a hidden option to suppress the warning when the -p/--password command line option is used.
22132235
# 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 +2255,18 @@ def main(cmdline, pkgpath):
22332255
config_file = default_cqlshrc
22342256

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

22382272
docspath = get_docspath(pkgpath)
@@ -2332,7 +2366,8 @@ def main(cmdline, pkgpath):
23322366
config_file=config_file,
23332367
cred_file=options.credentials,
23342368
username=options.username,
2335-
password=options.password))
2369+
password=options.password),
2370+
disable_history=options.disable_history)
23362371
except KeyboardInterrupt:
23372372
sys.exit('Connection aborted.')
23382373
except CQL_ERRORS as e:
@@ -2353,7 +2388,7 @@ def handle_sighup():
23532388

23542389
shell.init_history()
23552390
shell.cmdloop()
2356-
shell.save_history()
2391+
shell.save_history(options.disable_history)
23572392

23582393
if shell.batch_mode and shell.statement_error:
23592394
sys.exit(2)

0 commit comments

Comments
 (0)