vault: avoid shell=True in subprocess calls#2280
Merged
Merged
Conversation
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
View.take_action, thesubprocess.callinvocation now passespathdirectly instead ofstr(path), which will cause a mismatch with the updated tests (and may pass aPathobject tosubprocess); convertpathtostr(path)before including it in the argument list for consistency and correctness.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `View.take_action`, the `subprocess.call` invocation now passes `path` directly instead of `str(path)`, which will cause a mismatch with the updated tests (and may pass a `Path` object to `subprocess`); convert `path` to `str(path)` before including it in the argument list for consistency and correctness.
## Individual Comments
### Comment 1
<location path="osism/commands/vault.py" line_range="107" />
<code_context>
if not os.path.isabs(path):
path = os.path.join("/opt/configuration", path)
- subprocess.call(f"/usr/local/bin/ansible-vault decrypt {path}", shell=True)
+ subprocess.call(["/usr/local/bin/ansible-vault", "decrypt", path])
</code_context>
<issue_to_address>
**issue (bug_risk):** Align decrypt behavior with view by returning or handling the subprocess exit code.
Right now `decrypt` ignores the return value from `subprocess.call`, so the CLI can report success even if `ansible-vault decrypt` fails. Please propagate the exit code (e.g., return it from `take_action`) or raise on failure (e.g., `subprocess.run([...], check=True)`) so errors are visible to callers.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Both View.take_action and Decrypt.take_action passed user-supplied file paths into a shell command string with shell=True. A path containing shell metacharacters (e.g. a semicolon) could cause arbitrary command execution. Replace the string form with a list, which bypasses the shell entirely and passes the path as a literal argument: subprocess.call(["/usr/local/bin/ansible-vault", "view", path]) Apply the same fix to Decrypt.take_action, which had the identical pattern but was not part of the original PR that introduced View. Update existing tests to assert the list form and add a new test for Decrypt, which previously had no subprocess coverage. SecurityImpact: eliminates shell injection via crafted filenames AI-assisted: Claude Code Signed-off-by: Roger Luethi <luethi@osism.tech>
Decrypt.take_action() discarded the subprocess return code, while View.take_action() already returned it (added in d9384be). Callers that check $? or inspect the cliff return value would silently see success even when ansible-vault decrypt failed. Add 'return' so the exit code is propagated to the caller, matching the behaviour of View. Add a test that verifies a non-zero exit code from subprocess.call() is returned by take_action(). AI-assisted: Claude Code Signed-off-by: Roger Luethi <luethi@osism.tech>
Both View and Decrypt define 'path' with nargs="?", making it optional. When omitted, parsed_args.path is None, causing os.path.isabs(None) to raise a TypeError before any useful error message reaches the user. Add an explicit None check at the top of each take_action() that logs a clear error and returns 1, matching the error-handling style already used for FileNotFoundError and PermissionError in View. Add tests for both commands that confirm the exit code and error log when path is omitted. AI-assisted: Claude Code Signed-off-by: Roger Luethi <luethi@osism.tech>
8c93171 to
c71178a
Compare
15 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
shell=Truestring interpolation with list form inView.take_actionand
Decrypt.take_action— a user-supplied path containing shell metacharacters(e.g.
;) could cause arbitrary command executionansible-vaultexit code fromDecrypt.take_action, whichpreviously discarded it while
View.take_actionalready returned itViewandDecryptagainst a missingpathargument:nargs="?"makes the argument optional, but the code called
os.path.isabs(None)andraised an unhelpful
TypeErrorwhen it was omittedTest plan
pipenv run pytest tests/unit/commands/test_vault.py— all 11 tests passpipenv run pytest— full suite clean🤖 Generated with Claude Code