A GTK4 SSH-askpass in Zig
Creating a GTK4 SSH-askpass Utility using Zig
The author has developed a custom ssh-askpass implementation utilizing Zig 0.16 and GTK4. The primary motivation was to avoid the heavy X11 or KDE dependencies found in every existing option within the Gentoo repository. By writing manual bindings, the author successfully kept X11 entirely out of the build process.
The Problem Statement
The author operates a laptop running hardened Gentoo. Under normal circumstances, ssh-askpass is unnecessary because they primarily utilize -sk keys. However, a specific edge case exists:
When a program requires a passphrase for a standard ED25519 key but lacks a terminal (TTY) to request it, OpenSSH cannot prompt via a pipe. Instead, it executes the binary defined in the
SSH_ASKPASSenvironment variable to display a GUI window.
A common example of this is the go toolchain. When running go get to fetch a private module over SSH during a non-interactive build, the process lacks a TTY, triggering the need for a graphical prompt.
Requirements for a Solution
- Must be compatible with Wayland (Sway).
- Must not depend on X11 (Global
-XUSE flag). - Must have a minimal dependency footprint.
- Must provide a functional passphrase dialog.
Evaluating the Gentoo Ecosystem
A search for ssh-askpass in Portage reveals several candidates, but each presents a significant drawback:
| Package | Toolkit | X11 Dependency | Verdict |
|---|---|---|---|
kde-plasma/ksshaskpass | Qt/KDE | No | |
lxqt-base/lxqt-openssh-askpass | Qt/LXQt | Yes | |
net-misc/gnome-ssh-askpass | GTK | Likely | |
net-misc/ssh-askpass-fullscreen | GTK2 | Likely | |
net-misc/x11-ssh-askpass | X11 | Yes |
The "Dependency Hell" Analysis
The author's system uses a global -X flag, immediately disqualifying most options. While kde-plasma/ksshaskpass is the only one without a direct X11 requirement, the "cost" of installation is mathematically absurd for a simple prompt.
If we define the "Bloat Factor" as:
The result of running emerge -a kde-plasma/ksshaskpass is a massive chain of dependencies:
# Calculating dependencies...
[ ebuild N ] kde-frameworks/kf-env-6
[ ebuild N ] dev-libs/plasma-wayland-protocols-1.21.0
[ ebuild N ] dev-libs/qtkeychain-0.16.0
[ ebuild N ] kde-frameworks/ksecretd-services-6.27.0
[ ebuild N ] kde-frameworks/breeze-icons-6.27.0
[ ebuild N ] kde-frameworks/ki18n-6.27.0
[ ebuild N ] kde-frameworks/kconfig-6.27.0
[ ebuild N ] kde-frameworks/kcoreaddons-6.27.0
[ ebuild N ] kde-frameworks/kwidgetsaddons-6.27.0
[ ebuild N ] kde-frameworks/kdbusaddons-6.27.0
[ ebuild N ] kde-frameworks/kwindowsystem-6.27.0
[ ebuild N ] app-crypt/qca-2.3.10-r1
[ ebuild N ] kde-frameworks/karchive-6.27.0
[ ebuild N ] kde-frameworks/kguiaddons-6.27.0
[ ebuild N ] kde-frameworks/kdoctools-6.27.0
[ ebuild N ] kde-frameworks/kcolorscheme-6.27.0
[ ebuild N ] kde-frameworks/kcrash-6.27.0
[ ebuild N ] kde-frameworks/kservice-6.27.0
[ ebuild N ] kde-frameworks/kwallet-6.27.0
[ ebuild N ] kde-frameworks/kwallet-runtime-6.27.0
[ ebuild N ] kde-plasma/ksshaskpass-6.6.6
As a Sway user, installing a full KDE stack just to enter a password occasionally is unacceptable.
The LXQt Failure
The lxqt-base/lxqt-openssh-askpass option is even worse. Not only does it require X11, but it also triggers a slot conflict with the existing dev-qt/qtbase (which was compiled with -X).
# emerge -a lxqt-base/lxqt-openssh-askpass
[ebuild R ] x11-libs/libxkbcommon-1.13.2 USE="X*"
[ebuild N ] dev-util/lxqt-build-tools-2.4.0
[ebuild N ] x11-libs/xcb-util-renderutil-0.3.10
[ebuild N ] x11-libs/libXScrnSaver-1.2.5
...
# Result: Slot conflict due to X11 requirements.
The Decision Path
The following diagram illustrates the logic used to arrive at the custom Zig implementation:
By leveraging Zig and GTK4, the author created a lightweight, Wayland-native solution that respects the -X constraint without dragging in half of the KDE ecosystem.