Overview
This is Phase 3 of the SSH config parser enhancement roadmap. This phase focuses on adding support for command execution and automation features that enable sophisticated SSH workflows, automatic file synchronization, and environment setup.
Background
Options to Implement
1. LocalCommand + PermitLocalCommand ⭐⭐⭐⭐
Importance: High - Critical for automation workflows
Functionality:
- Execute local commands after successful SSH connection
- PermitLocalCommand must be enabled for security
- Command runs with user's shell on local machine
- Supports %h, %n, %p, %r, %u token substitution
Use Cases:
- Automatic file synchronization (rsync)
- Notification triggers
- Network configuration changes
- Smart card/security token operations
- Environment setup
Examples:
# Auto-sync files on connection
Host dev-server
PermitLocalCommand yes
LocalCommand rsync -av ~/project/ %h:~/project/
# Send notification
Host production
PermitLocalCommand yes
LocalCommand notify-send "Connected to %h"
# Reload smart card daemon
Host smartcard-required
PermitLocalCommand yes
LocalCommand gpg-connect-agent "scd serialno" "learn --force" /bye
Security Considerations:
- Commands can be dangerous - disabled by default
- Log all executed commands for audit
- Validate command paths (similar to ProxyCommand)
- Consider command timeout (30 seconds)
- Document security implications
Implementation:
- Add
permit_local_command: Option<bool> to SshHostConfig
- Add
local_command: Option<String> to SshHostConfig
- Note: bssh won't execute these (client-side), but should parse and store
2. RemoteCommand ⭐⭐⭐
Importance: Medium-High - Useful for specific workflows
Functionality:
- Execute command on remote host instead of starting shell
- Alternative to command-line argument
- Can be combined with RequestTTY
Use Cases:
- Auto-enter specific shell/environment
- Execute predefined tasks
- Container/tmux session attachment
- Automated testing
Examples:
# Auto-attach to tmux session
Host dev
RemoteCommand tmux attach -t dev || tmux new -s dev
RequestTTY yes
# Jump into specific directory and shell
Host project
RemoteCommand cd /srv/project && exec zsh
RequestTTY yes
# Run specific command
Host backup
RemoteCommand /usr/local/bin/backup.sh
RequestTTY no
Implementation:
- Add
remote_command: Option<String> to SshHostConfig
- Parse command (extends to end of line)
- No special validation needed
3. KnownHostsCommand ⭐⭐⭐
Importance: Medium - Important for dynamic environments
Functionality:
- Execute command to obtain host keys dynamically
- Supplements UserKnownHostsFile and GlobalKnownHostsFile
- Enables dynamic host key management
Use Cases:
- Cloud environments with dynamic instances
- Container-based infrastructure
- Certificate authority integration
- Centralized key management systems
Examples:
# Fetch keys from key management system
Host *.cloud.example.com
KnownHostsCommand /usr/local/bin/fetch-host-key %H
# Query certificate authority
Host *
KnownHostsCommand curl -s https://ca.example.com/hostkey/%H
Security Considerations:
- Validate executable path
- Command timeout (10 seconds)
- Log command execution
- Validate output format (known_hosts format)
Implementation:
- Add
known_hosts_command: Option<String> to SshHostConfig
- Validate command path (use existing validate_executable_string)
- Support %h, %H token substitution
- Note: Actual execution would be in client code, not parser
4. PermitRemoteOpen ⭐⭐⭐
Note: This was already included in Phase 2 (#44), but listing here for completeness as it relates to command execution workflows.
Additional Automation Options
5. ForkAfterAuthentication ⭐⭐
Functionality: Fork ssh into background after authentication
Use Case: Persistent background connections, multiplexing
6. SessionType ⭐⭐
Functionality: Specify session type (none, subsystem, default)
Use Case: SFTP subsystem, port forwarding only
7. StdinNull ⭐⭐
Functionality: Redirect stdin from /dev/null
Use Case: Background operations, scripting
Technical Implementation
Files to Modify
Parser:
src/ssh/ssh_config/parser.rs:95-460 - Add new option parsing
Types:
src/ssh/ssh_config/types.rs:22-68 - Add new fields to SshHostConfig
Security:
src/ssh/ssh_config/security.rs - Validate command strings
Implementation Details
// In types.rs
pub struct SshHostConfig {
// ... existing fields ...
// Command execution
pub permit_local_command: Option<bool>,
pub local_command: Option<String>,
pub remote_command: Option<String>,
pub known_hosts_command: Option<String>,
// Additional automation
pub fork_after_authentication: Option<bool>,
pub session_type: Option<String>,
pub stdin_null: Option<bool>,
}
// In parser.rs parse_option()
"permitlocalcommand" => {
if args.is_empty() {
anyhow::bail!("PermitLocalCommand requires a value at line {line_number}");
}
host.permit_local_command = Some(parse_yes_no(args[0], line_number)?);
}
"localcommand" => {
if args.is_empty() {
anyhow::bail!("LocalCommand requires a value at line {line_number}");
}
let command = args.join(" ");
// Security validation similar to ProxyCommand
validate_executable_string(&command, "LocalCommand", line_number)?;
host.local_command = Some(command);
}
"remotecommand" => {
if args.is_empty() {
anyhow::bail!("RemoteCommand requires a value at line {line_number}");
}
// No validation needed - runs on remote host
host.remote_command = Some(args.join(" "));
}
"knownhostscommand" => {
if args.is_empty() {
anyhow::bail!("KnownHostsCommand requires a value at line {line_number}");
}
let command = args.join(" ");
validate_executable_string(&command, "KnownHostsCommand", line_number)?;
host.known_hosts_command = Some(command);
}
"forkafterauthentication" => {
if args.is_empty() {
anyhow::bail!("ForkAfterAuthentication requires a value at line {line_number}");
}
host.fork_after_authentication = Some(parse_yes_no(args[0], line_number)?);
}
"sessiontype" => {
if args.is_empty() {
anyhow::bail!("SessionType requires a value at line {line_number}");
}
let value = args[0].to_lowercase();
if !["none", "subsystem", "default"].contains(&value.as_str()) {
anyhow::bail!("Invalid SessionType value at line {line_number}");
}
host.session_type = Some(value);
}
"stdinnull" => {
if args.is_empty() {
anyhow::bail!("StdinNull requires a value at line {line_number}");
}
host.stdin_null = Some(parse_yes_no(args[0], line_number)?);
}
Security Validation
Command Execution Security:
- Reuse existing
validate_executable_string() from security.rs
- Log warnings for potentially dangerous commands
- Document that PermitLocalCommand is disabled by default
- Add timeout recommendations in documentation
Token Substitution Support:
Implement token substitution for LocalCommand and KnownHostsCommand:
- %h - remote hostname (from config)
- %H - remote hostname (as specified on command line)
- %n - original hostname
- %p - remote port
- %r - remote username
- %u - local username
Testing Requirements
LocalCommand/PermitLocalCommand:
- Parse PermitLocalCommand yes/no
- Parse LocalCommand with tokens
- Validate command paths
- Security warnings for risky commands
RemoteCommand:
- Parse multi-word commands
- Handle special characters
- Integration with RequestTTY
KnownHostsCommand:
- Parse with path validation
- Token substitution in command
- Command string escaping
Additional Options:
- SessionType value validation
- ForkAfterAuthentication parsing
- StdinNull parsing
Success Criteria
Dependencies
References
Priority: Medium-High - Important for automation and workflows
Estimated Complexity: Medium - Straightforward parsing with security validation
Overview
This is Phase 3 of the SSH config parser enhancement roadmap. This phase focuses on adding support for command execution and automation features that enable sophisticated SSH workflows, automatic file synchronization, and environment setup.
Background
Options to Implement
1. LocalCommand + PermitLocalCommand ⭐⭐⭐⭐
Importance: High - Critical for automation workflows
Functionality:
Use Cases:
Examples:
Security Considerations:
Implementation:
permit_local_command: Option<bool>to SshHostConfiglocal_command: Option<String>to SshHostConfig2. RemoteCommand ⭐⭐⭐
Importance: Medium-High - Useful for specific workflows
Functionality:
Use Cases:
Examples:
Implementation:
remote_command: Option<String>to SshHostConfig3. KnownHostsCommand ⭐⭐⭐
Importance: Medium - Important for dynamic environments
Functionality:
Use Cases:
Examples:
Security Considerations:
Implementation:
known_hosts_command: Option<String>to SshHostConfig4. PermitRemoteOpen ⭐⭐⭐
Note: This was already included in Phase 2 (#44), but listing here for completeness as it relates to command execution workflows.
Additional Automation Options
5. ForkAfterAuthentication ⭐⭐
Functionality: Fork ssh into background after authentication
Use Case: Persistent background connections, multiplexing
6. SessionType ⭐⭐
Functionality: Specify session type (none, subsystem, default)
Use Case: SFTP subsystem, port forwarding only
7. StdinNull ⭐⭐
Functionality: Redirect stdin from /dev/null
Use Case: Background operations, scripting
Technical Implementation
Files to Modify
Parser:
src/ssh/ssh_config/parser.rs:95-460- Add new option parsingTypes:
src/ssh/ssh_config/types.rs:22-68- Add new fields to SshHostConfigSecurity:
src/ssh/ssh_config/security.rs- Validate command stringsImplementation Details
Security Validation
Command Execution Security:
validate_executable_string()from security.rsToken Substitution Support:
Implement token substitution for LocalCommand and KnownHostsCommand:
Testing Requirements
LocalCommand/PermitLocalCommand:
RemoteCommand:
KnownHostsCommand:
Additional Options:
Success Criteria
Dependencies
References
Priority: Medium-High - Important for automation and workflows
Estimated Complexity: Medium - Straightforward parsing with security validation