diff --git a/AGENTS.md b/AGENTS.md index d85557c..dcd43df 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -155,6 +155,8 @@ Use the narrowest command matching the changed area. ## Area-Specific Notes - `profile_desktop_common` manages shared Void desktop bootstrap, `emptty`, PAM hooks, dotfiles, mail bootstrap, and shared desktop tooling +- Void desktop user services now use `turnstile` with runit-backed definitions under `dotfiles/desktop/.config/service/`; session launchers refresh the shared turnstile env for GUI-aware services such as `emacs` +- `ssh-agent` on Void desktops now runs under a separate always-on per-user runsvdir rooted at `~/.local/runit/current`, with a stable socket under `~/.local/state/ssh-agent/socket` - `profile_desktop_i3` contains the X11/i3 session pieces - `profile_desktop_sway` contains the wlroots/Sway session pieces and deploys shared Sway + Waybar dotfiles - `profile_desktop_hyprland` contains the optional Hyprland/Wayland session pieces diff --git a/README.md b/README.md index f4780ab..48c6a6d 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,8 @@ Lo stato attuale del profilo desktop include, tra le altre cose: - sessione i3 su tutti i desktop Void e sessioni Sway/Hyprland opzionali su `nymph` - `emptty` con scelta sessione a login su `nymph` e default host-specific sugli altri desktop - pacchetti Void Linux e servizi runit +- `turnstile` per servizi utente agganciati alla sessione, incluso `emacs` come server per `emacsclient` +- `ssh-agent` come servizio runit utente always-on con socket stabile condiviso tra shell, SSH ed Emacs - Flatpak con remoto Flathub - GNOME Keyring e bootstrap della posta via script dedicato - `Waybar` separata per compositor (`config-sway.jsonc` e `config-hyprland.jsonc`) con `style.css` condiviso diff --git a/ansible/inventory/group_vars/desktop.yml b/ansible/inventory/group_vars/desktop.yml index 980183b..a7f38a8 100644 --- a/ansible/inventory/group_vars/desktop.yml +++ b/ansible/inventory/group_vars/desktop.yml @@ -19,6 +19,7 @@ desktop_common_packages: - pinentry-emacs - pinentry-gtk - rofi + - turnstile - udiskie - xfce-polkit - xdg-desktop-portal @@ -169,6 +170,10 @@ desktop_common_dotfiles: src: .config/opencode/ dest: .config/opencode/ mode: preserve + - name: Turnstile user services + src: .config/service/ + dest: .config/service/ + mode: preserve - name: Bash profile fragments src: .bashrc.d/ dest: .bashrc.d/ @@ -205,6 +210,10 @@ desktop_common_dotfiles: src: .local/bin/powermenu dest: .local/bin/powermenu mode: "0755" + - name: Turnstile environment update script + src: .local/bin/update-turnstile-env + dest: .local/bin/update-turnstile-env + mode: "0755" desktop_i3_dotfiles: - name: i3 config diff --git a/ansible/inventory/group_vars/void.yml b/ansible/inventory/group_vars/void.yml index 9de6390..bb42dc9 100644 --- a/ansible/inventory/group_vars/void.yml +++ b/ansible/inventory/group_vars/void.yml @@ -50,6 +50,7 @@ enabled_services: - libvirtd - nanoklogd - socklog-unix + - turnstiled - ufw - virtlockd - virtlogd diff --git a/ansible/roles/profile_desktop_common/tasks/main.yml b/ansible/roles/profile_desktop_common/tasks/main.yml index 743c972..3035cfe 100644 --- a/ansible/roles/profile_desktop_common/tasks/main.yml +++ b/ansible/roles/profile_desktop_common/tasks/main.yml @@ -311,6 +311,10 @@ loop: - path: "{{ user_home }}/.local" mode: "0755" + - path: "{{ user_home }}/.local/state" + mode: "0755" + - path: "{{ user_home }}/.local/state/ssh-agent" + mode: "0700" - path: "{{ user_home }}/.local/share" mode: "0755" - path: "{{ user_home }}/.local/share/keyrings" diff --git a/ansible/roles/services_runit/tasks/main.yml b/ansible/roles/services_runit/tasks/main.yml index ed6572a..33dd585 100644 --- a/ansible/roles/services_runit/tasks/main.yml +++ b/ansible/roles/services_runit/tasks/main.yml @@ -14,3 +14,68 @@ dest: "/var/service/{{ item }}" state: link loop: "{{ host_enabled_services | default([]) }}" + +- name: Ensure per-user runit directories exist + tags: [services, packages] + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: + - path: "{{ user_home }}/.local/runit" + mode: "0755" + - path: "{{ user_home }}/.local/runit/current" + mode: "0755" + - path: "{{ user_home }}/.local/runit/sv" + mode: "0755" + - path: "{{ user_home }}/.local/runit/sv/ssh-agent" + mode: "0755" + - path: "{{ user_home }}/.local/state" + mode: "0755" + - path: "{{ user_home }}/.local/state/ssh-agent" + mode: "0700" + +- name: Render per-user ssh-agent runit service + tags: [services, packages] + ansible.builtin.template: + src: ssh-agent.run.j2 + dest: "{{ user_home }}/.local/runit/sv/ssh-agent/run" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0755" + +- name: Enable per-user ssh-agent runit service + tags: [services, packages] + ansible.builtin.file: + src: "../sv/ssh-agent" + dest: "{{ user_home }}/.local/runit/current/ssh-agent" + state: link + owner: "{{ username }}" + group: "{{ user_group }}" + +- name: Ensure per-user runsvdir service directory exists + tags: [services, packages] + ansible.builtin.file: + path: "/etc/sv/runsvdir-{{ username }}" + state: directory + owner: root + group: root + mode: "0755" + +- name: Render per-user runsvdir system service + tags: [services, packages] + ansible.builtin.template: + src: runsvdir-user.run.j2 + dest: "/etc/sv/runsvdir-{{ username }}/run" + owner: root + group: root + mode: "0755" + +- name: Enable per-user runsvdir system service + tags: [services, packages] + ansible.builtin.file: + src: "/etc/sv/runsvdir-{{ username }}" + dest: "/var/service/runsvdir-{{ username }}" + state: link diff --git a/ansible/roles/services_runit/templates/runsvdir-user.run.j2 b/ansible/roles/services_runit/templates/runsvdir-user.run.j2 new file mode 100644 index 0000000..b4a217f --- /dev/null +++ b/ansible/roles/services_runit/templates/runsvdir-user.run.j2 @@ -0,0 +1,11 @@ +#!/bin/sh + +set -eu + +export USER="{{ username }}" +export HOME="{{ user_home }}" + +groups="$(id -Gn "$USER" | tr ' ' ':')" +svdir="$HOME/.local/runit/current" + +exec chpst -u "$USER:$groups" runsvdir "$svdir" diff --git a/ansible/roles/services_runit/templates/ssh-agent.run.j2 b/ansible/roles/services_runit/templates/ssh-agent.run.j2 new file mode 100644 index 0000000..9d5ada8 --- /dev/null +++ b/ansible/roles/services_runit/templates/ssh-agent.run.j2 @@ -0,0 +1,11 @@ +#!/bin/sh + +set -eu + +sockdir="{{ user_home }}/.local/state/ssh-agent" +sockpath="$sockdir/socket" + +mkdir -p "$sockdir" +rm -f "$sockpath" + +exec ssh-agent -D -a "$sockpath" diff --git a/dotfiles/desktop/.bashrc.d/15-runit-desktop.sh b/dotfiles/desktop/.bashrc.d/15-runit-desktop.sh new file mode 100644 index 0000000..9c579e4 --- /dev/null +++ b/dotfiles/desktop/.bashrc.d/15-runit-desktop.sh @@ -0,0 +1,2 @@ +export SVDIR="$HOME/.local/runit/current" +export SSH_AUTH_SOCK="$HOME/.local/state/ssh-agent/socket" diff --git a/dotfiles/desktop/.bashrc.d/25-emacs-client-desktop.sh b/dotfiles/desktop/.bashrc.d/25-emacs-client-desktop.sh new file mode 100644 index 0000000..4427f00 --- /dev/null +++ b/dotfiles/desktop/.bashrc.d/25-emacs-client-desktop.sh @@ -0,0 +1,15 @@ +if command -v emacsclient >/dev/null 2>&1; then + ec() { + emacsclient -c -n "$@" || { + printf '%s\n' "Emacs server is not available. Log into a graphical session and ensure the turnstile-managed 'emacs' service is running." >&2 + return 1 + } + } + + et() { + emacsclient -t "$@" || { + printf '%s\n' "Emacs server is not available. Ensure the turnstile-managed 'emacs' service is running in your graphical session." >&2 + return 1 + } + } +fi diff --git a/dotfiles/desktop/.config/hypr/hyprland.conf b/dotfiles/desktop/.config/hypr/hyprland.conf index 380b314..0db9525 100644 --- a/dotfiles/desktop/.config/hypr/hyprland.conf +++ b/dotfiles/desktop/.config/hypr/hyprland.conf @@ -7,6 +7,7 @@ $locker = ~/.local/bin/lock-session $screenshot = ~/.local/bin/screenshot-wayland exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP +exec-once = ~/.local/bin/update-turnstile-env exec-once = dex --autostart --environment Hyprland exec-once = gnome-keyring-daemon --start --components=secrets exec-once = ~/.local/bin/setup-gtk-theme @@ -79,6 +80,7 @@ windowrulev2 = float,class:^(blueman-manager)$ bind = $mod, Return, exec, $terminal bind = $mod SHIFT, Return, exec, $fallback_terminal +bind = $mod SHIFT, E, exec, emacsclient -c -n bind = $mod, D, exec, $menu bind = $mod SHIFT, V, exec, pavucontrol bind = $mod SHIFT, F, exec, thunar diff --git a/dotfiles/desktop/.config/i3/config b/dotfiles/desktop/.config/i3/config index 85b9e4b..e15e30e 100644 --- a/dotfiles/desktop/.config/i3/config +++ b/dotfiles/desktop/.config/i3/config @@ -58,6 +58,9 @@ bindsym $mod+Return exec --no-startup-id /usr/bin/alacritty # Emergency terminal fallback bindsym $mod+Shift+Return exec --no-startup-id st +# Emacs client +bindsym $mod+Shift+e exec --no-startup-id emacsclient -c -n + # Launcher #bindsym $mod+d exec --no-startup-id "rofi -modi drun,run -show drun" bindsym $mod+d exec --no-startup-id "rofi -show drun -theme ~/.config/rofi/config.rasi" diff --git a/dotfiles/desktop/.config/service/emacs/run b/dotfiles/desktop/.config/service/emacs/run new file mode 100755 index 0000000..89d48a0 --- /dev/null +++ b/dotfiles/desktop/.config/service/emacs/run @@ -0,0 +1,11 @@ +#!/bin/sh + +set -eu + +export SSH_AUTH_SOCK="$HOME/.local/state/ssh-agent/socket" + +if [ -n "${TURNSTILE_ENV_DIR:-}" ]; then + exec chpst -e "$TURNSTILE_ENV_DIR" emacs --fg-daemon +fi + +exec emacs --fg-daemon diff --git a/dotfiles/desktop/.config/sway/config b/dotfiles/desktop/.config/sway/config index 20664a1..b2f7444 100644 --- a/dotfiles/desktop/.config/sway/config +++ b/dotfiles/desktop/.config/sway/config @@ -14,6 +14,7 @@ font pango:Liberation Mono 10 # Session bootstrap exec dbus-update-activation-environment --systemd WAYLAND_DISPLAY DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE XCURSOR_THEME XCURSOR_SIZE exec systemctl --user import-environment WAYLAND_DISPLAY DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE XCURSOR_THEME XCURSOR_SIZE +exec ~/.local/bin/update-turnstile-env exec dex --autostart --environment sway exec gnome-keyring-daemon --start --components=secrets exec ~/.local/bin/setup-gtk-theme @@ -71,6 +72,7 @@ set $right l # App launchers and window actions bindsym $mod+Return exec $terminal bindsym $mod+Shift+Return exec $fallback_terminal +bindsym $mod+Shift+e exec emacsclient -c -n bindsym $mod+d exec $menu bindsym $mod+Shift+v exec pavucontrol bindsym $mod+Shift+f exec thunar diff --git a/dotfiles/desktop/.local/bin/start-hyprland-session b/dotfiles/desktop/.local/bin/start-hyprland-session index 03afa8d..acb8a82 100644 --- a/dotfiles/desktop/.local/bin/start-hyprland-session +++ b/dotfiles/desktop/.local/bin/start-hyprland-session @@ -12,11 +12,12 @@ session_name=${1##*/} export XDG_CURRENT_DESKTOP="$session_name" export XDG_SESSION_DESKTOP="$session_name" export XDG_SESSION_TYPE=wayland +export SSH_AUTH_SOCK="$HOME/.local/state/ssh-agent/socket" exec dbus-run-session sh -eu -c ' umask 077 printf "%s\n" "$DBUS_SESSION_BUS_ADDRESS" > "$HOME/.dbus-session-bus-address" - eval "$(ssh-agent -s)" >/dev/null gpgconf --launch gpg-agent + "$HOME/.local/bin/update-turnstile-env" exec "$@" ' sh "$@" diff --git a/dotfiles/desktop/.local/bin/start-sway-session b/dotfiles/desktop/.local/bin/start-sway-session index 5558857..025fe6a 100644 --- a/dotfiles/desktop/.local/bin/start-sway-session +++ b/dotfiles/desktop/.local/bin/start-sway-session @@ -11,6 +11,7 @@ session_name=sway export XDG_CURRENT_DESKTOP="$session_name" export XDG_SESSION_DESKTOP="$session_name" export XDG_SESSION_TYPE=wayland +export SSH_AUTH_SOCK="$HOME/.local/state/ssh-agent/socket" if [ "${SWAY_UNSUPPORTED_GPU:-0}" = "1" ]; then set -- sway --unsupported-gpu @@ -21,7 +22,7 @@ fi exec dbus-run-session sh -eu -c ' umask 077 printf "%s\n" "$DBUS_SESSION_BUS_ADDRESS" > "$HOME/.dbus-session-bus-address" - eval "$(ssh-agent -s)" >/dev/null gpgconf --launch gpg-agent + "$HOME/.local/bin/update-turnstile-env" exec "$@" ' sh "$@" diff --git a/dotfiles/desktop/.local/bin/update-turnstile-env b/dotfiles/desktop/.local/bin/update-turnstile-env new file mode 100755 index 0000000..f2a79c7 --- /dev/null +++ b/dotfiles/desktop/.local/bin/update-turnstile-env @@ -0,0 +1,18 @@ +#!/bin/sh + +set -eu + +if ! command -v turnstile-update-runit-env >/dev/null 2>&1; then + exit 0 +fi + +turnstile-update-runit-env \ + DISPLAY \ + WAYLAND_DISPLAY \ + XAUTHORITY \ + DBUS_SESSION_BUS_ADDRESS \ + SSH_AUTH_SOCK \ + XDG_CURRENT_DESKTOP \ + XDG_SESSION_DESKTOP \ + XDG_SESSION_TYPE \ + SWAYSOCK >/dev/null 2>&1 || true diff --git a/dotfiles/desktop/.xinitrc b/dotfiles/desktop/.xinitrc index f6248ce..13d7831 100755 --- a/dotfiles/desktop/.xinitrc +++ b/dotfiles/desktop/.xinitrc @@ -10,11 +10,12 @@ session_name=${1##*/} export XDG_CURRENT_DESKTOP="$session_name" export XDG_SESSION_DESKTOP="$session_name" export XDG_SESSION_TYPE=x11 +export SSH_AUTH_SOCK="$HOME/.local/state/ssh-agent/socket" exec dbus-run-session sh -eu -c ' umask 077 printf "%s\n" "$DBUS_SESSION_BUS_ADDRESS" > "$HOME/.dbus-session-bus-address" - eval "$(ssh-agent -s)" >/dev/null gpgconf --launch gpg-agent + "$HOME/.local/bin/update-turnstile-env" exec "$@" ' sh "$@"