github timhartmann7/omnyssh v1.1.2
OmnySSH v1.1.2

28 days ago

Features

  • Hosts imported from ~/.ssh/config can be edited in the desktop app. Imported hosts were shown read-only, so changing a port or a username for one meant deleting it from your SSH config and adding it again by hand — while the terminal app had allowed the edit all along. Editing one now saves your own copy, which OmnySSH uses from then on; ~/.ssh/config is still never written to. The form says so before you save, since later changes you make to that file stop reaching the host once it has been adopted. The bastion and key path the app parsed are carried over even though the form cannot show them, so an adopted ProxyJump host keeps connecting through its jump server. Deleting is still offered for your own hosts only — there is nothing of an import to remove — and deleting a copy you adopted brings the imported version back, which the confirmation now tells you.
  • Watch a host by a port check instead of an SSH login. Firewalls, switches and other appliances answer SSH but have no shell to read top or free from, so monitoring could only ever fail on them — and log in again every cycle to find that out. A host can now be set to TCP port check: OmnySSH opens a connection to the port and closes it, with no login and no commands. Its card shows reachable / unreachable in place of the metric tiles, rather than tiles for numbers nobody collected. Set it in the host form — tcp (the host's SSH port) or tcp:PORT in the terminal app, a dropdown in the desktop app. Existing hosts are untouched and stay on SSH monitoring. ICMP is not offered yet: unprivileged ping is unavailable on the Linux packaging most people use.

Bug Fixes

  • The dropdowns in the desktop app look like the rest of the app. The monitoring picker on the host form and the scope picker on the snippet form were plain <select> elements, which every platform draws itself: on macOS that is a light grey popup button with a double arrow, sitting on the dark form as a bright hole a good deal shorter than the fields around it, and no styling on the element had any effect on it. Windows and Linux drew their own versions of the same mismatch. Both now use one control that strips the platform chrome and matches the text fields exactly, in either theme. The list that opens is still the operating system's, so keyboard, screen readers and touch behave as they always did.
  • Nerd Font glyphs render instead of empty boxes. The desktop terminal asked for a list of system monospace fonts, none of which carry the glyphs that prompts like starship and powerlevel10k, or eza --icons, draw from — so those came out as boxes even for people who had a Nerd Font installed. Common Nerd Font families are now named as fallbacks, behind the regular monospace ones so ordinary text keeps the same typeface and spacing. Snippet output and SFTP file previews get the same treatment, since both show text straight from the server. You still need a Nerd Font installed; the app does not ship one.
  • The desktop app reopens at the size and position you left it. Every launch reset the window to 1100x720 wherever the system chose to put it, so a window sized to your screen — or moved to a second monitor — had to be set up again each time. Size and position now persist. Visibility deliberately does not: the window still starts hidden and appears once the interface has painted, so restoring geometry never brings back the blank frame at launch.
  • macOS: the window buttons no longer sit across the edge of a collapsed sidebar. The red/amber/green cluster is positioned by the system against the window, not by the app's layout, and it is wider than the collapsed sidebar was — so the sidebar's edge fell on the green button and left it over the content area while the other two stayed on the sidebar. The collapsed sidebar is now wide enough to hold the whole cluster on macOS. Windows and Linux draw their own title bar and keep the narrower one.
  • Hosts split across Include files are imported. A relative pattern — Include conf.d/*.conf, the form nearly every split-config guide prints — was looked for in whatever directory the app happened to be launched from, which for the desktop app started from Finder or the application menu is /. Nothing matched, so every host defined in ~/.ssh/conf.d was missing and had to be added by hand. Those patterns now resolve against ~/.ssh, the way ssh itself resolves them. Four things in the same code path were fixed alongside it: full glob patterns work (?, [abc], a wildcard in a directory name, and more than one * in a file name), several pathnames on one Include line are all read instead of none, a quoted path keeps its spaces, and an Include written inside a Host block no longer swallows that host's remaining settings. An Include that matches nothing is written to the log rather than passing in silence.
  • CPU no longer reads ~91–100 % on an idle server whose system language isn't English. Monitoring reads the idle percentage from top and shows the rest as used. On a server set to a language with a comma decimal separator, top prints 99,1 id, and the parser split that line on commas — reading the idle value as 1 and reporting 99 % used on a machine doing nothing. The same servers could show RAM and Disk as N/A, because free and df translate the labels being looked for, and the process list could come back empty. The monitoring commands now run in a fixed locale, and the CPU parsers understand a decimal comma on their own for hosts where that cannot be set. Process names keep the server's own character set.
  • A host that answers SSH but not shell commands is no longer re-logged-in every 30 seconds. Network appliances — firewalls, switches — authenticate fine but cannot run top or free, and a round of failed metric commands was treated as a dead connection. The retry delay was reset on every successful login, so it never grew past its first step: one login every 30 seconds, indefinitely, and as often as every 10 seconds in the desktop app, whose refresh timer also cut the retry delay short. The delay now escalates properly and is left alone by the refresh timer — the trade-off being that a manual refresh no longer cuts a retry delay short, so a host that has been unreachable for a while retries on its own schedule (at most five minutes). Separately, a device that ignores SSH keepalives was being disconnected after 30 seconds even while its commands still worked; connections are now held open, with liveness still bounded by the keepalive limit.
  • ProxyJump hosts now connect through their bastion. A host with ProxyJump in ~/.ssh/config was parsed but never routed: the terminal refused to open it, while metrics, SFTP, snippets and key setup quietly dialled the target address direct — which for an internal host meant every connection failed or, worse, landed somewhere else on that address. Every native SSH path now walks the jump chain the way ssh -J does, connecting and authenticating each bastion in turn and tunnelling the next hop over it.
    • The jump alias is resolved against your host list, so ProxyJump public-proxy picks up that entry's HostName, User, Port and IdentityFile. An alias that matches no entry is used as a literal hostname.
    • Multi-hop values (ProxyJump first,second), inline user@host:port overrides, IPv6 literals, bastions that are themselves behind a bastion, and the ProxyJump none opt-out all behave as OpenSSH does — including its precedence rule that only the first hop of a list contributes bastions of its own. Chains that loop, or run past ten hops, are reported instead of hanging.
    • A ProxyJump that cannot be resolved — a malformed hop, an unreadable host list, a cycle — fails the connection. It never falls back to dialling the target address, which is the very thing that made the old behaviour dangerous.
    • Each hop's host key is checked against known_hosts under its own name, and each hop authenticates with the usual agent → identity file → default keys → password order. Every hop, including the tunnel opened on a bastion, is bound by the same ten-second budget, so a firewalled target cannot leave a host stuck on "connecting".
    • A bastion you renamed after importing it is still found by the alias other entries name it with.
    • One-click SSH key setup works for hosts behind a bastion: its verification steps now get the time the longer connection needs, and running out of time after password authentication has been disabled rolls the server back instead of reporting a clean failure.
    • Editing an imported host in the TUI no longer drops its ProxyJump, nor the name it was imported under: the form has no field for either, so the saved copy used to lose the bastion, and a second edit lost the imported name — which brought the ~/.ssh/config entry back as a duplicate card and left any other host's ProxyJump pointing at an alias nothing answered to. The GUI already preserved both.
  • Windows: the console-window fix from 1.1.1 actually reaches you this time. The fix was in that release's source, but the Windows installer published under the v1.1.1 tag was an artifact left over from an earlier build — so the .exe it installed was the 1.1.0 one, still linked as a console application, and none of 1.1.1's Windows fixes (the console window, the white launch flash, the ssh-keygen console) were in it. The release now discards anything a previous build left behind, publishes only the bundle it just produced for the version being released, and refuses to publish at all if the desktop binary is not linked as a GUI application or if any installer is missing.
  • The update banner links to the release instead of offering an install that cannot run. Self-update has no endpoints configured yet, so the Install button reported "Self-update is not available yet" on every platform. It now opens the release page in your browser; Install returns when the desktop updater is wired up.
  • A Linux desktop build that opens to an empty window restarts itself once. On some graphics setups WebKit cannot start its hardware renderer, so the app opened as an empty dark frame and stayed that way, with the error going to a terminal nobody launched it from. If the interface still has not loaded twelve seconds in, OmnySSH now restarts itself once with software rendering. This covers the .deb and .rpm as well as the .AppImage: the failure is WebKit meeting a particular graphics driver rather than anything the AppImage does, and install.sh now prefers the .rpm on the distributions where it is reported most, so leaving the native packages out would have moved the affected people onto the one build with no answer for it. A launch that loads normally is untouched, a launch you started with WEBKIT_DISABLE_DMABUF_RENDERER set yourself is left alone, and the restart can happen only once. macOS and Windows are unaffected.
  • Editing a host no longer drops every other host's monitoring session. Putting the monitoring mode on the host form meant the terminal app had to restart its polling pool after an edit, since a running poller does not pick up a changed address, port or mode. It restarted the whole pool for any edit at all, so fixing a typo in one host's notes reconnected and re-authenticated every server on the dashboard. The pool is now restarted only when the edit moved something a connection is actually made from — the name, address, user, port, key, password or monitoring mode. Editing tags or notes leaves every session where it was.
  • macOS: install.sh no longer installs an older copy of the app. The installer read the mount point out of hdiutil's output by stopping at the first space. When a volume called OmnySSH was already mounted — because you had opened the .dmg in Finder first, or because an earlier run was interrupted — macOS mounts the new one as OmnySSH 1, and the truncated path pointed back at the one already there. The script then copied that older app into /Applications and reported success.
  • Linux: a .deb that could not be installed is no longer reported as installed. apt-get install -f resolves an unsatisfiable dependency by removing the package dpkg has just unpacked, and exits successfully having done so — which the installer read as a working install and announced as one, leaving you with the message and nothing else. It now asks dpkg what is actually installed, and falls back to the AppImage when the package did not survive, the way the .rpm path already did.
  • Linux: installing the .deb removes the AppImage it replaces. The .rpm path already did this and the .deb path did not. The package installs to /usr/bin under its own name while an AppImage from an earlier run sits in /usr/local/bin, which comes first on the default PATH — so omnyssh on the command line kept starting the old build, and the application menu carried two identical entries.
  • ARM64 Linux and Termux install the terminal app instead of nothing. No desktop build exists for those targets, and curl … | sh — the command the README prints — installs the desktop app by default. It warned and exited without installing anything, although the terminal app ships for exactly those targets. It now installs that instead. A desktop build that does exist and fails to install still fails rather than quietly falling back.

Packaging

  • A native .rpm for Fedora and other RPM distributions. Releases now carry OmnySSH-x86_64.rpm alongside the .AppImage and .deb, and install.sh prefers it on dnf-based systems — it lands in your application menu and uninstalls with dnf remove, no FUSE involved. The package names the WebKitGTK 4.1, JavaScriptCore and GTK 3 libraries it links, so dnf resolves them from your own distribution instead of the app carrying a second copy. Distributions that ship no WebKitGTK 4.1 at all, such as RHEL 9 and its rebuilds, will refuse the package; install.sh then tries the AppImage there.
  • The Linux packages are named omny-ssh. The bundler derives the package name from the product name, so the .deb and .rpm register as omny-ssh even though the files are called OmnySSH-x86_64.deb and OmnySSH-x86_64.rpm. Uninstall with dnf remove omny-ssh or apt remove omny-ssh.

Don't miss a new omnyssh release

NewReleases is sending notifications on new releases.