Skip to content

feat: SSH certificate authentication support#327

Merged
ellie merged 9 commits intomainfrom
ellie/ssh-cert-handling
Jan 10, 2026
Merged

feat: SSH certificate authentication support#327
ellie merged 9 commits intomainfrom
ellie/ssh-cert-handling

Conversation

@ellie
Copy link
Member

@ellie ellie commented Jan 8, 2026

Change Summary

Add SSH certificate authentication support with per-block certificate configuration. Users can now specify identity keys and certificates directly in SSH connect blocks, with local-only storage for per-user credentials on shared runbooks.

Motivation and details

This feature enables more flexible SSH authentication scenarios:

  • Per-block certificate/key configuration via a settings modal
  • Support for three identity key modes: default (system keys), path-based, and paste-content
  • Certificate validation with user-friendly warnings for expired/not-yet-valid certs
  • Automatic fallback to key authentication when cert auth fails
  • Integration tests with Docker infrastructure for certificate testing

Tasks

  • Regenerated TS-RS bindings (if any ts(export) structs have changed)
  • Updated the documentation in docs/ (if any application behavior has changed)
  • I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle

ellie and others added 8 commits January 7, 2026 12:36
Adds support for SSH certificate-based authentication with automatic
fallback to key-based auth when certificates are invalid or expired.

- Auto-detect companion certificate files (e.g., id_ed25519-cert.pub)
- Validate certificate timing (expiry, not-yet-valid)
- Emit warning events for certificate issues while allowing connection
- Show toast notifications for certificate problems
- Document known limitation: agent-held certificates not supported

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add certificate config UI (path/paste modes) to SSH settings modal
- Improve certificate validation with expiry/not-yet-valid warnings
- Add integration tests for certificate authentication
- Update Docker test infrastructure with CA key generation
- Fix toast overflow for long messages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace 50-line manual calendar math with OffsetDateTime::from().to_string()
from the time crate (already a dependency).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
De-duplicate the 3-line publickey auth pattern that was repeated
in each certificate validation fallback path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace nested match statements with if-let early returns for
clearer control flow in key_auth_from_content_with_cert and
key_auth_with_cert_config.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Some WorkspaceError variants (WorkspaceNotWatched, RunbookNotFound, etc.)
don't have a message field. Use type guard to safely access it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ellie ellie force-pushed the ellie/ssh-cert-handling branch from 42b5442 to 17d96d9 Compare January 8, 2026 02:37
@ellie ellie marked this pull request as ready for review January 8, 2026 02:41
@ellie
Copy link
Member Author

ellie commented Jan 9, 2026

@greptile plz

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 9, 2026

Greptile Overview

Greptile Summary

This PR adds SSH certificate authentication support with per-block configuration. Users can specify identity keys and certificates via three modes: default (system keys), path-based, or paste-content. The implementation includes:

Core Features:

  • Automatic certificate detection using OpenSSH naming convention (id_ed25519-cert.pub)
  • Certificate validation (expiry, not-yet-valid) with automatic fallback to key auth
  • Per-block identity key/certificate configuration stored in local KV (not synced)
  • Integration tests with Docker SSH server for cert scenarios
  • User notifications for certificate issues via toast messages

Architecture:

  • session.rs: Certificate parsing, validation, and authentication with fallback
  • pool.rs: Connection pool propagates AuthResult with warnings
  • ssh_pool.rs: Actor handles auth warnings for PTY sessions
  • SshConnect.tsx: UI for configuring identity keys and certificates
  • Event system: Certificate warnings flow from backend → grand central → notifications

Key Issue Found:
SSH certificate warnings are emitted for PTY sessions but not for command execution (ssh_pool.rs:616-618). This creates an inconsistency where users running commands won't see certificate warnings, but interactive shell users will.

Important Files Changed

File Analysis

Filename Score Overview
crates/atuin-desktop-runtime/src/ssh/session.rs 4/5 Adds SSH certificate authentication with auto-detection, validation, and fallback. Has minor style concerns around principal validation warnings.
crates/atuin-desktop-runtime/src/ssh/ssh_pool.rs 3/5 Updates pool to propagate auth warnings to PTY sessions but NOT to exec commands - inconsistency that should be addressed.
crates/atuin-desktop-runtime/src/ssh/pool.rs 4/5 Correctly propagates certificate config and auth warnings through connection pool. Returns default AuthResult for cached connections.
src/components/runbooks/editor/blocks/ssh/SshConnect.tsx 4/5 Adds UI for identity key and certificate configuration. Uses KV store for per-user credentials. Could benefit from client-side validation.

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.

6 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 616 to 618
result = pool_guard.connect_with_config(&host, Some(username.as_str()), None, Some(connect_cancel_rx), ssh_config.as_ref()) => {
tracing::trace!("SSH connection to {host} with username {username} successful");
result.map_err(SshPoolConnectionError::from)
result.map(|(session, _auth_result)| session).map_err(SshPoolConnectionError::from)
Copy link
Contributor

Choose a reason for hiding this comment

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

The auth_result returned from connect_with_config contains warnings about certificate issues, but in the Exec message handler, these warnings are discarded (.map(|(session, _auth_result)| session)).

This means SSH certificate warnings (expired cert, load failed, etc.) are NOT emitted to the user when executing commands via SSH - they're only emitted when opening PTY sessions (see line 815 in OpenPty handler).

This is an inconsistency: users running commands over SSH won't see certificate warnings, but users opening interactive shells will. Consider emitting warnings here as well, similar to how it's done in the OpenPty handler (lines 815+ and terminal.rs lines 309-351).

Copy link
Member Author

Choose a reason for hiding this comment

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

@claude fix that one please

Copy link

@claude claude bot Jan 9, 2026

Choose a reason for hiding this comment

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

Claude finished @ellie's task in 6m 13s —— View job


Fixed SSH certificate warning inconsistency ✓

Todo:

  • Read ssh_pool.rs to understand current Exec handler implementation
  • Read OpenPty handler to understand warning emission pattern
  • Read terminal.rs to understand the full warning flow
  • Design solution approach
  • Implement warning emission in Exec handler
  • Update script.rs to handle and emit warnings
  • Verify the code compiles
  • Commit and push changes

Summary:

The issue was that SSH certificate warnings were being emitted for PTY sessions but NOT for command execution, creating an inconsistency where users running commands wouldn't see certificate warnings.

Changes made:

  1. Added warnings_tx optional channel parameter to the Exec message in ssh_pool.rs
  2. Modified the Exec handler (line 618) to capture auth_result.warnings instead of discarding them
  3. Warnings are sent through the new channel to the caller after SSH connection
  4. Updated script.rs to receive and emit these warnings as GC events (matching the terminal.rs pattern at lines 309-351)

This ensures SSH certificate warnings (expired, not-yet-valid, load failed) are now consistently emitted for both PTY sessions AND command execution flows.

Commit: 3b5ad0c

Certificate authentication warnings were being emitted for PTY sessions
but not for command execution (exec). This caused an inconsistency where
users running commands wouldn't see certificate warnings, but interactive
shell users would.

Changes:
- Added warnings_tx channel to Exec message in ssh_pool.rs
- Modified Exec handler to capture and send auth_result.warnings
- Updated script.rs to receive and emit warnings as GC events
- Warnings now flow consistently for both PTY and exec operations

Fixes issue identified in code review where auth_result was discarded
on line 618 during exec connection.

Co-authored-by: Ellie Huxtable <ellie@users.noreply.github.com>
@ellie ellie force-pushed the ellie/ssh-cert-handling branch from 3b5ad0c to f3ba5aa Compare January 9, 2026 23:56
@ellie ellie merged commit b270f10 into main Jan 10, 2026
9 checks passed
@ellie ellie deleted the ellie/ssh-cert-handling branch January 10, 2026 00:03
@github-actions github-actions bot locked and limited conversation to collaborators Jan 10, 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