Skip to content

Commit 88e31eb

Browse files
committed
Enabled ruff S ruleset for security checks
Strategically disabled on various lines in cmd2 code where we are using subprocess.Popen() in a way it doesn't like as well as when we are using asserts intentionally like in transcript testing.
1 parent 26cf7b9 commit 88e31eb

File tree

6 files changed

+15
-17
lines changed

6 files changed

+15
-17
lines changed

cmd2/argparse_completer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,14 +292,14 @@ def update_mutex_groups(arg_action: argparse.Action) -> None:
292292

293293
# If we're in a flag REMAINDER arg, force all future tokens to go to that until a double dash is hit
294294
if flag_arg_state is not None and flag_arg_state.is_remainder:
295-
if token == '--':
295+
if token == '--': # noqa: S105
296296
flag_arg_state = None
297297
else:
298298
consume_argument(flag_arg_state)
299299
continue
300300

301301
# Handle '--' which tells argparse all remaining arguments are non-flags
302-
if token == '--' and not skip_remaining_flags:
302+
if token == '--' and not skip_remaining_flags: # noqa: S105
303303
# Check if there is an unfinished flag
304304
if (
305305
flag_arg_state is not None

cmd2/argparse_custom.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,9 +1046,6 @@ def _format_usage(
10461046
req_parts = re.findall(part_regexp, req_usage)
10471047
opt_parts = re.findall(part_regexp, opt_usage)
10481048
pos_parts = re.findall(part_regexp, pos_usage)
1049-
assert ' '.join(req_parts) == req_usage
1050-
assert ' '.join(opt_parts) == opt_usage
1051-
assert ' '.join(pos_parts) == pos_usage
10521049

10531050
# End cmd2 customization
10541051

cmd2/cmd2.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,7 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False) -> None:
13271327
with self.sigint_protection:
13281328
import subprocess
13291329

1330-
pipe_proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE, stdout=self.stdout)
1330+
pipe_proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE, stdout=self.stdout) # noqa: S602
13311331
pipe_proc.communicate(final_msg.encode('utf-8', 'replace'))
13321332
except BrokenPipeError:
13331333
# This occurs if a command's output is being piped to another process and that process closes before the
@@ -2589,7 +2589,7 @@ def _run_cmdfinalization_hooks(self, stop: bool, statement: Optional[Statement])
25892589
# caused by certain binary characters having been printed to it.
25902590
import subprocess
25912591

2592-
proc = subprocess.Popen(['stty', 'sane'])
2592+
proc = subprocess.Popen(['stty', 'sane']) # noqa: S603, S607
25932593
proc.communicate()
25942594

25952595
data = plugin.CommandFinalizationData(stop, statement)
@@ -2862,7 +2862,7 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
28622862
kwargs['executable'] = shell
28632863

28642864
# For any stream that is a StdSim, we will use a pipe so we can capture its output
2865-
proc = subprocess.Popen( # type: ignore[call-overload]
2865+
proc = subprocess.Popen( # type: ignore[call-overload] # noqa: S602
28662866
statement.pipe_to,
28672867
stdin=subproc_stdin,
28682868
stdout=subprocess.PIPE if isinstance(self.stdout, utils.StdSim) else self.stdout, # type: ignore[unreachable]
@@ -4212,7 +4212,7 @@ def do_shell(self, args: argparse.Namespace) -> None:
42124212
# still receive the SIGINT since it is in the same process group as us.
42134213
with self.sigint_protection:
42144214
# For any stream that is a StdSim, we will use a pipe so we can capture its output
4215-
proc = subprocess.Popen( # type: ignore[call-overload]
4215+
proc = subprocess.Popen( # type: ignore[call-overload] # noqa: S602
42164216
expanded_command,
42174217
stdout=subprocess.PIPE if isinstance(self.stdout, utils.StdSim) else self.stdout, # type: ignore[unreachable]
42184218
stderr=subprocess.PIPE if isinstance(sys.stderr, utils.StdSim) else sys.stderr, # type: ignore[unreachable]
@@ -4425,7 +4425,7 @@ def py_quit() -> None:
44254425
if py_code_to_run:
44264426
try:
44274427
interp.runcode(py_code_to_run) # type: ignore[arg-type]
4428-
except BaseException: # noqa: BLE001
4428+
except BaseException: # noqa: BLE001, S110
44294429
# We don't care about any exception that happened in the Python code
44304430
pass
44314431

@@ -4448,7 +4448,7 @@ def py_quit() -> None:
44484448
# Since quit() or exit() raise an EmbeddedConsoleExit, interact() exits before printing
44494449
# the exitmsg. Therefore, we will not provide it one and print it manually later.
44504450
interp.interact(banner=banner, exitmsg='')
4451-
except BaseException: # noqa: BLE001
4451+
except BaseException: # noqa: BLE001, S110
44524452
# We don't care about any exception that happened in the interactive console
44534453
pass
44544454
finally:

cmd2/transcript.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ def _test_transcript(self, fname: str, transcript: Iterator[str]) -> None:
108108
# Read the expected result from transcript
109109
if ansi.strip_style(line).startswith(self.cmdapp.visible_prompt):
110110
message = f'\nFile {fname}, line {line_num}\nCommand was:\n{command}\nExpected: (nothing)\nGot:\n{result}\n'
111-
assert not result.strip(), message
111+
assert not result.strip(), message # noqa: S101
112112
# If the command signaled the application to quit there should be no more commands
113-
assert not stop, stop_msg
113+
assert not stop, stop_msg # noqa: S101
114114
continue
115115
expected_parts = []
116116
while not ansi.strip_style(line).startswith(self.cmdapp.visible_prompt):
@@ -124,13 +124,13 @@ def _test_transcript(self, fname: str, transcript: Iterator[str]) -> None:
124124

125125
if stop:
126126
# This should only be hit if the command that set stop to True had output text
127-
assert finished, stop_msg
127+
assert finished, stop_msg # noqa: S101
128128

129129
# transform the expected text into a valid regular expression
130130
expected = ''.join(expected_parts)
131131
expected = self._transform_transcript_expected(expected)
132132
message = f'\nFile {fname}, line {line_num}\nCommand was:\n{command}\nExpected:\n{expected}\nGot:\n{result}\n'
133-
assert re.match(expected, result, re.MULTILINE | re.DOTALL), message
133+
assert re.match(expected, result, re.MULTILINE | re.DOTALL), message # noqa: S101
134134

135135
def _transform_transcript_expected(self, s: str) -> str:
136136
r"""Parse the string with slashed regexes into a valid regex.

cmd2/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,8 @@ def _reader_thread_func(self, read_stdout: bool) -> None:
627627
write_stream = self._stderr
628628

629629
# The thread should have been started only if this stream was a pipe
630-
assert read_stream is not None
630+
if read_stream is None:
631+
raise ValueError("read_stream is None")
631632

632633
# Run until process completes
633634
while self._proc.poll() is None:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ select = [
206206
"RET", # flake8-return (various warnings related to implicit vs explicit return statements)
207207
"RSE", # flake8-raise (warn about unnecessary parentheses on raised exceptions)
208208
# "RUF", # Ruff-specific rules (miscellaneous grab bag of lint checks specific to Ruff)
209-
# "S", # flake8-bandit (security oriented checks, but extremely pedantic - do not attempt to apply to unit test files)
209+
"S", # flake8-bandit (security oriented checks, but extremely pedantic - do not attempt to apply to unit test files)
210210
# "SIM", # flake8-simplify (rules to attempt to simplify code)
211211
# "SLF", # flake8-self (warn when protected members are accessed outside of a class or file)
212212
"SLOT", # flake8-slots (warn about subclasses that should define __slots__)

0 commit comments

Comments
 (0)