Reference

Architecture

Bastion Terminal is a local-first desktop application built on Tauri 2, React 18, and a Rust core. This page describes the runtime architecture: how the layers talk, where state lives, and which subsystems are involved in a typical SSH session.

High-level diagram

UI (React · TypeScript)
    │
    │  typed Tauri IPC (commands + events)
    ▼
Rust core (src-tauri)
    ├── hosts / groups / snippets   → SQLite (bastion.db)
    ├── private keys                → OS keychain
    ├── SSH service                 → russh / ssh2
    ├── local PTY                   → portable-pty
    ├── updater                     → signed Tauri updater
    └── settings / theme registry
    │
    ▼
OS layer: keychain, OS updater, terminal PTY, OS notifications

Frontend (React + Vite)

The UI is a single-page React app, organized around feature folders: components/, stores/, hooks/, lib/, and styles/. State is managed with zustand; forms use react-hook-form + zod.

xterm.js renders the terminal grid, with addons for fit, web links, and the search overlay. Themes are CSS custom properties on :root[data-theme=…] and are applied to the xterm theme on switch.

Rust core

The Rust crate lives in src-tauri/ and exposes commands to the frontend over typed Tauri IPC. Major responsibilities:

  • Hosts / groups / snippets: CRUD on top of SQLite via sqlx. Migrations live in src-tauri/migrations/.
  • Private keys: generated, imported, and stored in the OS keychain (Credential Manager / Keychain / Secret Service). The key material never crosses the IPC boundary as plaintext.
  • SSH service: manages sessions, reads and stores known-host fingerprints, and performs password and private-key auth. SSH agent authentication is not enabled in this build.
  • Local PTY: opens a shell on this machine using portable-pty. Used by the local terminal alongside remote sessions.
  • Updater: Tauri updater settings in tauri.conf.json, including a public key. Version 1.1.0 reads latest.json from downloads.bastion.hexifytech.com.

State and storage

DataStorage
Host metadata, groups, snippets, settingsLocal SQLite (bastion.db)
Private keysOS keychain
PasswordsMemory only (active connect)
Terminal scrollbackIn-memory
Update checkslatest.json on downloads.bastion.hexifytech.com.

IPC contract

The frontend never reads from disk directly. Every read and write goes through a typed Tauri command in src/lib/. Commands are namespaced by feature:

  • hosts.*: list, get, create, update, delete, reorder
  • groups.*: same shape, scoped to groups
  • snippets.*: list, get, run, save
  • ssh.*: open session, auth, fingerprint, disconnect
  • keys.*: generate, import, list, delete
  • settings.*: get, update, theme, font, cursor, scrollback

Security boundaries

  • The webview cannot reach the filesystem, network, or OS keychain directly. All access goes through Rust commands.
  • Private keys are read from the keychain inside the SSH service and are never logged or returned to the frontend.
  • Passwords live in memory for the active connect and are dropped on disconnect.
  • Update artifacts are verified against the embedded public key before install.

Test pyramid

  • Vitest: unit tests for stores, hooks, and lib helpers.
  • Playwright: critical UI flows in the Vite web preview.
  • Rust integration tests: SSH flows, fingerprint verification, keychain storage.
  • Phase 7 QA matrix: manual and automated hardening before release.