Skip to content

feat: add SSH connection settings modal with identity key configuration#325

Merged
ellie merged 5 commits intomainfrom
ellie/ssh-connect-config
Jan 7, 2026
Merged

feat: add SSH connection settings modal with identity key configuration#325
ellie merged 5 commits intomainfrom
ellie/ssh-connect-config

Conversation

@ellie
Copy link
Member

@ellie ellie commented Jan 7, 2026

Change Summary

Adds a settings modal to SSH Connect blocks enabling fine-grained connection configuration. Users can override connection details (user/hostname/port) and configure identity key authentication per-user without affecting other team members.

Motivation and Details

The modal provides three identity key modes: use SSH config/agent (default), specify a key path from ~/.ssh, or paste key content directly. Identity keys are stored locally in block-local KV storage, not synced to other users, allowing each team member to authenticate with their own credentials for shared runbooks. SSH connections are automatically invalidated when credentials change. The UI shows validation warnings when only one of user/hostname is configured.

Tasks

  • Documentation updated in docs/docs/blocks/network/ssh.md
  • Error handling added for file selection and key loading
  • Visual validation indicators for incomplete configs
  • I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 7, 2026

Greptile Summary

  • Adds SSH connection settings modal to SSH Connect blocks with fine-grained authentication configuration including identity key modes, connection overrides, and per-user credential storage
  • Implements comprehensive backend SSH configuration system with block-level overrides, automatic connection invalidation when credentials change, and enhanced error handling for SSH operations
  • Updates SSH-related blocks (Script, Terminal) to support new configuration system and provides better error feedback via toast notifications

Important Files Changed

Filename Overview
src/components/runbooks/editor/blocks/ssh/SshConnect.tsx Added comprehensive settings modal with identity key configuration, connection overrides, and local storage for credentials
crates/atuin-desktop-runtime/src/ssh/session.rs Implemented SSH authentication with block-provided identity keys and connection configuration overrides
backend/src/commands/blocks.rs Added SSH connection invalidation when identity keys change and enhanced block KV storage compatibility
crates/atuin-desktop-runtime/src/ssh/pool.rs Extended connection pool to support per-block SSH configuration and host-based connection invalidation
backend/src/commands/ssh.rs New file providing SSH key discovery functionality to list and identify private keys from ~/.ssh directory

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@ellie ellie force-pushed the ellie/ssh-connect-config branch from eadee40 to 6f1ff3d Compare January 7, 2026 06:00
ellie and others added 4 commits January 6, 2026 23:24
Adds fine-grained control over SSH connections via a settings modal:
- User/hostname/port overrides that take precedence over the quick input
- Identity key configuration (none/path/paste) stored locally per-user
- Automatic SSH connection invalidation when credentials change
- Visual validation for incomplete user/hostname configs
- Credential selection from ~/.ssh with key type detection

The identity key is stored in block-local KV, not synced, allowing each user
to authenticate with their own credentials for shared runbooks.

🤖 Generated with Claude Code

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Remove dual-format handling - just use the original direct kv::get.

🤖 Generated with Claude Code

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
KV stores JSON objects directly. Get as Value and serialize to string
for the runtime to parse.

🤖 Generated with Claude Code

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@ellie ellie force-pushed the ellie/ssh-connect-config branch from d45d6e2 to 8cdeeac Compare January 7, 2026 07:24
format!() already returns String, so .into() was redundant.

🤖 Generated with Claude Code

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@ellie
Copy link
Member Author

ellie commented Jan 7, 2026

@greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Greptile Summary

Adds SSH connection settings modal enabling per-block configuration of user/hostname/port and identity key authentication. Settings are split between synced (connection details) and local-only (identity keys) storage to support team collaboration with individual credentials.

Key changes:

  • New list_ssh_keys Tauri command scans ~/.ssh for private keys
  • SSH Connect block gains modal UI with three identity key modes: config/agent, key path, or paste content
  • Block-local KV storage holds identity keys per-user (not synced)
  • SSH connections invalidated when identity key changes via notify_block_kv_value_changed
  • Identity key authentication tried first, before agent/config/defaults
  • DocumentSshConfig context item provides rich SSH configuration to runtime

Issues found:

  • Binary key file handling may fail in detect_key_type (reads as UTF-8 string)
  • Shell escaping incomplete in exec_and_capture (missing newline/backslash handling)
  • Validation edge case: empty user/hostname props might pass when they shouldn't

Important Files Changed

File Analysis

Filename Score Overview
backend/src/commands/ssh.rs 3/5 new list_ssh_keys command with key type detection; has potential issue with binary key file handling
crates/atuin-desktop-runtime/src/blocks/ssh_connect.rs 3/5 adds user/hostname/port overrides and identity key config; validation logic has edge case with empty props
crates/atuin-desktop-runtime/src/ssh/session.rs 3/5 adds open_with_config, authenticate_with_config, and key_auth_from_content for block-level SSH overrides; shell escaping incomplete
crates/atuin-desktop-runtime/src/ssh/ssh_pool.rs 4/5 adds disconnect_by_host for invalidating connections and config override support throughout pool operations
src/components/runbooks/editor/blocks/ssh/SshConnect.tsx 4/5 comprehensive settings modal UI with identity key modes (none/path/paste) and connection overrides; minor optimization opportunity

Comment on lines +94 to +96
fn detect_key_type(path: &PathBuf) -> Option<String> {
let content = fs::read_to_string(path).ok()?;
let first_line = content.lines().next()?;
Copy link
Contributor

Choose a reason for hiding this comment

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

reading file content as string can fail for binary key files (e.g., SSH keys with binary headers).

Suggested change
fn detect_key_type(path: &PathBuf) -> Option<String> {
let content = fs::read_to_string(path).ok()?;
let first_line = content.lines().next()?;
fn detect_key_type(path: &PathBuf) -> Option<String> {
let content = fs::read(path).ok()?;
let first_line = std::str::from_utf8(&content[..content.iter().position(|&b| b == b'\n').unwrap_or(content.len())]).ok()?;

Comment on lines +208 to +214
let has_user = resolved_user.as_ref().is_some_and(|u| !u.is_empty());
let has_hostname = resolved_hostname.as_ref().is_some_and(|h| !h.is_empty());
if has_user != has_hostname {
return Err(
"SSH settings require both user and hostname to be set (or neither)".into(),
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

validation only checks if resolved values are non-empty after resolution, but doesn't validate the actual values. Empty user or hostname props with non-empty userHost would pass this check when they shouldn't

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 7, 2026

Additional Comments (1)

crates/atuin-desktop-runtime/src/ssh/session.rs
shell escaping is incomplete - doesn't handle newlines, tabs, or backslashes

        let shell_command = format!("sh -c '{}'", command.replace('\\', "\\\\").replace('\'', "'\"'\"'").replace('\n', "\\n"));

@ellie ellie merged commit 33df312 into main Jan 7, 2026
12 checks passed
@ellie ellie deleted the ellie/ssh-connect-config branch January 7, 2026 08:01
@github-actions github-actions bot locked and limited conversation to collaborators Jan 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant