Wayland Altında GPG Commit İmzalama Çilesi ve Rofi Entegrasyonu

Güvenli ve doğrulanabilir bir yazılım geliştirme iş akışı için Git commit’lerini GPG (GNU Privacy Guard) ile imzalamak günümüzde standart bir pratik haline geldi. Ancak bu güvenli limana ulaşmaya çalışırken, kullandığınız pencere yöneticisi ve terminal arayüzleri bazen süreci tamamen kilitleyebilir.

NixOS ve Hyprland (Wayland) tabanlı minimalist masaüstü ortamımda, terminal üzerinden git commit atmaya çalıştığımda veya bir dosyayı GPG ile imzalamak istediğimde sık sık şu hata ile karşılaşıyordum:

error: gpg failed to sign the data
fatal: failed to write commit object

Bazen de süreç hiçbir çıktı vermeden terminali tamamen kilitliyor, arka planda bir zaman aşımı (Timeout) veya “İşlem iptal edildi” (Operation cancelled) hatasıyla sonlanıyordu. En sık karşılaşılan hata çıktısı ise şu şekildedir:

gpg: signing failed: Inappropriate ioctl for device

Bu yazıda, bu kilitlenmenin teknik nedenini, geleneksel çevre değişkeni çözümlerinin neden yetersiz kaldığını ve arayüz seviyesinde nasıl kalıcı bir çözüm ürettiğimizi inceleyeceğiz.

Teşhis: TTY, GPG_TTY ve pinentry-curses Çıkmazı

GPG ile bir veriyi imzalamak istediğinizde, özel anahtarınızın (private key) şifresini çözmek için sistem sizden parola ister. Bu parolayı güvenli bir şekilde almak için gnupg-agent, pinentry adı verilen küçük arayüz araçlarını tetikler.

Benim önceki konfigürasyonumda pinentry paketi olarak terminal tabanlı olan pinentry-curses seçiliydi:

# Eski ve sorunlu yapılandırma
programs.gnupg.agent = {
  enable = true;
  pinentryPackage = pkgs.pinentry-curses;
};

Klasik Geçici Çözüm: GPG_TTY

Normal şartlarda, terminal tabanlı şifre sorucuların çalışabilmesi için işletim sisteminin GPG’ye hangi terminal cihazını (TTY) kullanacağını söylemesi gerekir. Bunun için kabuk (shell) profiline şu satır eklenir:

export GPG_TTY=$(tty)

Bu çevre değişkeni, basit terminal oturumlarında sorunu çözer. Ancak aşağıdaki senaryolarda GPG_TTY tamamen etkisiz kalır:

  1. Girdi Çakışması (stdin/pipe): GPG imzalama işlemi bir borulama (pipe) veya Git gibi bir ara katman tarafından tetiklendiğinde, standart girdi (stdin) zaten başka bir süreç tarafından meşgul ediliyor olabilir. pinentry-curses bu durumda klavye girdisini yakalayamaz.
  2. Git Kancaları (Hooks) ve Arka Plan Süreçleri: Bir commit sırasında çalışan asenkron git kancaları (örneğin pre-commit linter’ları) veya IDE entegrasyonları çalıştığında, süreç aktif bir TTY olmadan (non-interactive) tetiklenir. GPG_TTY tanımlı olsa bile ortada etkileşime geçilebilecek fiziksel bir TTY olmadığı için Inappropriate ioctl for device hatası kaçınılmaz olur.
  3. Wayland Odaklanma Sorunu: Hyprland gibi döşemeli (tiling) pencere yöneticilerinde, parola istemcisi görünmez bir TTY tünelinde asılı kalır. Kullanıcıya şifre sorulamaz ve ajan zaman aşımına uğrar.

Çözüm: Arayüzü Grafik Katmanına Taşımak (pinentry-rofi)

Bu TTY kilitlenmesini aşmanın en kararlı yolu, parola giriş ekranını terminalin içinden kurtarıp masaüstünün genel grafik katmanına taşımaktır. Hyprland/Wayland ortamında ana uygulama başlatıcı olarak Wofi tercih etsem de, parola sorma arayüzü olarak hafif ve bağımsız bir grafiksel pop-up sunan pinentry-rofi aracını entegre ettim.

NixOS’un modüler yapısı sayesinde, GPG ajanın şifre istemcisini doğrudan bu grafiksel popup penceresine yönlendirmek son derece basittir.

modules/core/gpg.nix dosyamı şu şekilde güncelledim:

{ config, pkgs, ... }:

{
  # GPG (GNU Privacy Guard) Yapılandırması
  programs.gnupg.agent = {
    enable = true;
    enableSSHSupport = true;
    # Çözüm: GUI tabanlı ve Hyprland uyumlu pinentry-rofi geçişi
    pinentryPackage = pkgs.pinentry-rofi; 
    settings = {
      default-cache-ttl = 28800;     # Parolayı 8 saat boyunca hafızada tut
      max-cache-ttl = 28800;
    };
  };

  # GPG paketini sistem geneline ekle
  environment.systemPackages = [ pkgs.gnupg ];
}

Bu değişiklik uygulandığında (nixos-rebuild switch), imzalama işlemi tetiklendiği an ekranın ortasında temiz, odaklanma sorunu yaşamayan ve klavye girdisini doğrudan yakalayan bir grafiksel şifre kutusu açılmaya başladı. Terminalin stdin durumu ne olursa olsun, parola grafik katmanında girildiği için kilitlenmeler tamamen ortadan kalktı.

Ekstra Kazanımlar ve Mimari İnce Ayarlar

Bu geçişi yaparken sistem mimarisinde doğruladığım ve optimize ettiğim birkaç kritik nokta daha oldu:

1. SOPS-Nix ve GPG İzolasyonu

Sistem genelindeki gizli sırları (API anahtarları, şifreler vb.) Git üzerinde şifreli tutmak için kullandığım sops-nix modülünün bu değişiklikten etkilenip etkilenmeyeceğini kontrol ettim. sops-nix arka planda GPG yerine modern age şifreleme altyapısını ve kimlik doğrulaması için doğrudan ~/.ssh/id_ed25519 SSH anahtarını kullanıyor. Dolayısıyla GPG ajanındaki bu pinentry değişimi, sistemin sops-nix sır yönetimini tamamen izole tutarak hiçbir yan etki yaratmadı.

2. Çoklu Anahtar Öncelik Çıkmazı

Cüzdanınızda birden fazla GPG anahtarı olduğunda (örneğin Git commit imzalamak için eski bir RSA anahtarı ve genel şifrelemeler için yeni bir ED25519 anahtarı):

Eğer manuel işlemlerde spesifik anahtarınızı zorlamak istiyorsanız, komutlarınıza --local-user parametresini eklemeyi unutmayın:

gpg --local-user YOUR_SPECIFIC_KEY_ID --sign document.txt

Sonuç

Masaüstü ortamınızı Wayland ve tiling window manager (Hyprland, Sway vb.) üzerine kuruyorsanız, terminal tabanlı araçların (curses varyantları) TTY odağı ve borulama süreçlerinde yaratabileceği kilitlenmeleri hesaba katmalısınız. GPG şifre sorma adımını pinentry-rofi gibi grafiksel bir arayüze taşımak, deklaratif sistem bütünlüğünü bozmadan iş akışınızı kesintisiz hale getirmenin en temiz yoludur.


Kaynaklar


İlgili:

EOF.