Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src-tauri/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ impl AgentManager {
#[cfg(not(target_os = "windows"))]
let mut child = {
use std::borrow::Cow;
use std::env;

// Build shell command with proper quoting for command and arguments
let escaped_command = shell_escape::escape(Cow::Borrowed(config.command.as_str()));
Expand All @@ -92,7 +93,12 @@ impl AgentManager {
format!("{} {}", escaped_command, quoted_args.join(" "))
};

Command::new("/bin/sh")
// Use login shell to get full PATH environment (especially important on macOS)
// This ensures commands like npx, node, claude etc. are found
let shell = env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string());
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

Potential security concern: Using the $SHELL environment variable without validation means any value set in that variable will be executed. While this typically contains a legitimate shell path, in compromised or misconfigured environments, it could point to:

  • A malicious executable
  • A non-existent path (though this would just fail)
  • A script that doesn't behave like a shell

Consider adding validation to ensure $SHELL points to a known, safe shell executable (e.g., checking against a whitelist of common shells like /bin/bash, /bin/zsh, /usr/bin/fish, etc.) or at minimum verifying the executable exists and is executable before using it.

Suggested change
let shell = env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string());
let shell = env::var("SHELL")
.ok()
.and_then(|shell_path| {
if shell_path.is_empty() {
return None;
}
let path = std::path::Path::new(&shell_path);
match std::fs::metadata(path) {
Ok(metadata) if metadata.is_file() => Some(shell_path),
_ => None,
}
})
.unwrap_or_else(|| "/bin/sh".to_string());

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Applied the suggested validation for the $SHELL environment variable. The code now:

  • Validates the shell basename against a whitelist of known shells (sh, bash, zsh, fish, dash, ksh, tcsh, csh)
  • Checks that the file exists and has execute permissions
  • Falls back to /bin/sh if validation fails

Commit: 0f31574 (initial), with additional improvements in my local changes that can't be pushed due to branch protection rules.


Command::new(shell)
.arg("-l") // login shell to load user's profile and PATH
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

Using the -l (login shell) flag could cause unintended side effects. Login shells execute profile scripts (.bash_profile, .zprofile, etc.) which may contain:

  • Interactive prompts or commands expecting user input
  • Commands that assume they're running in an interactive terminal
  • Expensive initialization scripts that slow down agent startup
  • Side effects like logging to files or changing directories

Consider using a non-login, non-interactive shell instead by just sourcing the necessary PATH. For example, you could:

  1. Use -c without -l and manually source PATH from common locations
  2. Or use an approach that reads PATH from the user's shell config without executing the entire profile

If you keep the -l flag, test with various shells (bash, zsh, fish) to ensure compatibility, as not all shells handle -l the same way when combined with -c.

Copilot uses AI. Check for mistakes.
Comment on lines +98 to +101
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

The -l flag behavior varies across different shells. While bash and zsh support -l -c together, other shells may not:

  • fish shell uses -l differently and may not work correctly with this pattern
  • dash (common on many Linux systems as /bin/sh) doesn't support the -l flag
  • Some exotic shells may not support -l at all

When $SHELL is not set and defaults to /bin/sh, the -l flag may fail on systems where /bin/sh is dash or another minimal shell. Consider:

  1. Checking which shell is being used and adjusting flags accordingly
  2. Or handling the error case more gracefully if the shell doesn't support -l
  3. Or testing if the shell supports -l before using it

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Addressed by only using the -l flag for shells that support it (bash, zsh, fish). The code now detects the shell basename and skips -l for sh/dash/ksh/tcsh/csh. Falls back to /bin/sh without -l when $SHELL is not set or invalid.

.arg("-c")
.arg(&shell_command)
.envs(&config.env)
Comment on lines +101 to 104
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

When using a login shell with -l, the environment variables set via .envs(&config.env) may be overridden by the user's profile scripts (.bash_profile, .zprofile, etc.). If the profile scripts set PATH or other variables, they will take precedence over the values passed from the parent process.

This could lead to unexpected behavior where environment variables configured in the agent's config are ignored. Consider:

  1. Setting environment variables after the shell initialization (though this isn't easily possible with the current approach)
  2. Or documenting this behavior so users know their profile scripts take precedence
  3. Or exporting the configured environment variables in the shell command itself to ensure they're set

Copilot uses AI. Check for mistakes.
Expand Down
Loading