Skip to content

feat(rules): support command extraction from subshells#23

Merged
fohte merged 5 commits intomainfrom
fohte/impl-runok-init-cmd-extraction
Feb 12, 2026
Merged

feat(rules): support command extraction from subshells#23
fohte merged 5 commits intomainfrom
fohte/impl-runok-init-cmd-extraction

Conversation

@fohte
Copy link
Owner

@fohte fohte commented Feb 11, 2026

Why

  • The permission engine needs extract_commands() to decompose compound commands inside subshells ((...)) so that each individual command can be evaluated

What

  • Recursively expand subshell nodes so that (cmd1 && cmd2) | cmd3 correctly yields three separate commands
  • Add tests for logical operator chains, subshells, process substitution, heredocs, and whitespace handling

Open with Devin

extract_commands() did not recurse into subshell nodes like `(cmd1 && cmd2)`,
treating the entire parenthesized group as a single opaque command string.
This prevented the permission engine from evaluating individual commands
within subshells.

Add `"subshell"` to the set of compound constructs that collect_commands()
recurses into, so `(cmd1 && cmd2) | cmd3` correctly yields three separate
commands. Also add test coverage for logical operator chains, subshells,
process substitution preservation, heredocs, and whitespace handling.
@gemini-code-assist
Copy link

Summary of Changes

Hello @fohte, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the command parsing capabilities by enabling the extract_commands function to correctly identify and decompose individual commands within subshell constructs. This enhancement is vital for the permission engine, allowing it to accurately evaluate and apply permissions to all constituent commands, even when they are nested or part of complex shell expressions.

Highlights

  • Subshell Command Extraction: The collect_commands function was updated to recursively process subshell nodes, enabling the decomposition of compound commands found within subshell expressions.
  • Expanded Test Coverage: New test cases were introduced to validate the extract_commands function's behavior across various scenarios, including logical operator chains, nested subshells, process substitutions, heredocs, and diverse whitespace handling.
Changelog
  • src/rules/command_parser.rs
    • Enabled recursive command extraction from subshell nodes within the collect_commands function.
    • Expanded test coverage for extract_commands to include logical operator chains, subshells, process substitution, heredocs, and various whitespace scenarios.
Activity
  • No specific activity (comments, reviews, or progress updates) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly extends the command extraction logic to support subshells by recursively traversing subshell nodes in the AST. The implementation is straightforward and effective. The accompanying tests cover several important cases, including logical operators, subshells in pipelines, process substitution, and heredocs. I've suggested a couple of improvements to the new tests to make them more robust and descriptive, covering more complex nesting and whitespace scenarios. Overall, this is a solid contribution that addresses the stated goal.

Comment on lines +525 to +526
let result = extract_commands(" cmd1 && cmd2 ").unwrap();
assert_eq!(result, vec!["cmd1", "cmd2"]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current whitespace test is good, but it could be more comprehensive. It mainly tests the trim() on the overall input string in extract_commands. To also validate the trim() on individual command segments within collect_commands, consider a more complex case involving internal whitespace and subshells.

Suggested change
let result = extract_commands(" cmd1 && cmd2 ").unwrap();
assert_eq!(result, vec!["cmd1", "cmd2"]);
let result = extract_commands(" cmd1 && cmd2 | ( cmd3 ) ").unwrap();
assert_eq!(result, vec!["cmd1", "cmd2", "cmd3"]);

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

Reviewer pointed out that `extract_nested_subshell` was misleading
(it tested a subshell in a logical chain, not truly nested subshells)
and that whitespace tests lacked subshell coverage.

Rename to `extract_subshell_in_logical_chain`, add a genuine nested
subshell test using `(cmd1 | (cmd2 ; cmd3))`, and add a whitespace
test combining operators with subshells.
Individual #[test] functions with identical assert patterns were
scattered across multiple sections, making it harder to scan and
extend the test suite.

Consolidate into parameterized rstest groups: compound commands,
subshell, special constructs, whitespace, and error cases.
@fohte fohte merged commit 07cafa8 into main Feb 12, 2026
2 checks passed
@fohte fohte deleted the fohte/impl-runok-init-cmd-extraction branch February 12, 2026 12:19
@fohte-bot fohte-bot bot mentioned this pull request Feb 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant