diff --git a/Dockerfile b/Dockerfile index 1a03b08..50b68dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,11 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"] ENV DEBIAN_FRONTEND=noninteractive ENV EDITOR=nvim \ - VISUAL=nvim + VISUAL=nvim \ + XDG_CONFIG_HOME=/home/node/.config \ + XDG_CACHE_HOME=/home/node/.cache \ + XDG_DATA_HOME=/home/node/.local/share \ + XDG_STATE_HOME=/home/node/.local/state RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ @@ -42,7 +46,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ neovim \ nodejs \ novnc \ - openbox \ openssh-server \ pipx \ procps \ @@ -67,8 +70,39 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ x11-xserver-utils \ x11vnc \ xauth \ - xterm \ xvfb \ + xfce4-session \ + xfwm4 \ + xfdesktop4 \ + xfce4-settings \ + xfce4-terminal \ + thunar \ + plank \ + autocutsel \ + greybird-gtk-theme \ + elementary-xfce-icon-theme \ + fonts-noto-core \ + fonts-noto-color-emoji \ + dbus-user-session \ + xclip \ + && rm -rf /var/lib/apt/lists/* + +# Chromium: Ubuntu 24.04 only ships a snap stub, so pull the real .deb from +# the Debian Sid repo (pinned low so it only satisfies chromium itself). +RUN printf '%s\n' \ + "deb [arch=amd64] http://deb.debian.org/debian sid main" \ + >/etc/apt/sources.list.d/debian-sid.list \ + && printf '%s\n' \ + "Package: *" \ + "Pin: release a=unstable" \ + "Pin-Priority: 10" \ + "" \ + "Package: chromium chromium-common chromium-sandbox" \ + "Pin: release a=unstable" \ + "Pin-Priority: 500" \ + >/etc/apt/preferences.d/chromium \ + && apt-get update \ + && apt-get install -y --no-install-recommends chromium \ && rm -rf /var/lib/apt/lists/* RUN useradd --create-home --shell /bin/bash node \ @@ -84,6 +118,11 @@ RUN useradd --create-home --shell /bin/bash node \ && ln -sf /usr/bin/nvim /usr/local/bin/vim \ && ln -sf /usr/bin/nvim /usr/local/bin/vi +COPY desktop/assets /opt/desktop/assets +COPY desktop/xfce /opt/desktop/xfce +COPY desktop/plank /opt/desktop/plank +COPY desktop/scripts /opt/desktop/scripts + COPY sshd_config /etc/ssh/sshd_config COPY microagent-init.sh /usr/local/bin/microagent-init COPY microagent-desktop-session.sh /usr/local/bin/microagent-desktop-session @@ -95,6 +134,7 @@ COPY terminfo/xterm-ghostty.terminfo /tmp/xterm-ghostty.terminfo COPY terminfo/xterm-kitty.terminfo /tmp/xterm-kitty.terminfo RUN chmod 755 /usr/local/bin/microagent-init /usr/local/bin/microagent-desktop-session /usr/local/bin/microagent-network-up \ + && chmod 755 /opt/desktop/scripts/apply-desktop-profile.sh \ && chown node:node /home/node/.zshrc /home/node/.bashrc /home/node/.profile \ && usermod -s /usr/bin/zsh node \ && install -d /opt/zsh/pure \ diff --git a/defaults/.bashrc b/defaults/.bashrc index 3b2c3aa..e6b6ced 100644 --- a/defaults/.bashrc +++ b/defaults/.bashrc @@ -27,7 +27,6 @@ computer_prompt_name() { export EDITOR="${EDITOR:-nvim}" export VISUAL="${VISUAL:-nvim}" alias vim='nvim' -alias vi='nvim' alias ls='eza --group-directories-first --icons=auto' alias la='eza -a --group-directories-first --icons=auto' alias ll='eza -lah --git --group-directories-first --icons=auto' diff --git a/defaults/.zshrc b/defaults/.zshrc index 88e6ee2..abe6926 100644 --- a/defaults/.zshrc +++ b/defaults/.zshrc @@ -48,7 +48,6 @@ fi export EDITOR="${EDITOR:-nvim}" export VISUAL="${VISUAL:-nvim}" alias vim='nvim' -alias vi='nvim' alias ls='eza --group-directories-first --icons=auto' alias la='eza -a --group-directories-first --icons=auto' alias ll='eza -lah --git --group-directories-first --icons=auto' diff --git a/desktop/assets/wallpaper.png b/desktop/assets/wallpaper.png new file mode 100644 index 0000000..8e07274 Binary files /dev/null and b/desktop/assets/wallpaper.png differ diff --git a/desktop/plank/dock1/launchers/chromium.dockitem b/desktop/plank/dock1/launchers/chromium.dockitem new file mode 100644 index 0000000..2884b73 --- /dev/null +++ b/desktop/plank/dock1/launchers/chromium.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/chromium.desktop diff --git a/desktop/plank/dock1/launchers/thunar.dockitem b/desktop/plank/dock1/launchers/thunar.dockitem new file mode 100644 index 0000000..1bfd173 --- /dev/null +++ b/desktop/plank/dock1/launchers/thunar.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/thunar.desktop diff --git a/desktop/plank/dock1/launchers/xfce4-terminal.dockitem b/desktop/plank/dock1/launchers/xfce4-terminal.dockitem new file mode 100644 index 0000000..2fc64b3 --- /dev/null +++ b/desktop/plank/dock1/launchers/xfce4-terminal.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/xfce4-terminal.desktop diff --git a/desktop/plank/dock1/settings b/desktop/plank/dock1/settings new file mode 100644 index 0000000..4f4fa1a --- /dev/null +++ b/desktop/plank/dock1/settings @@ -0,0 +1,21 @@ +[PlankDockPreferences] +Alignment=3 +AutoPinning=true +CurrentWorkspaceOnly=false +DockItems=xfce4-terminal.dockitem;;thunar.dockitem;;chromium.dockitem +HideDelay=0 +HideMode=3 +IconSize=48 +ItemsAlignment=3 +LockItems=true +Monitor= +Offset=0 +PinnedOnly=false +Position=3 +PressureReveal=false +ShowDockItem=false +Theme=Transparent +TooltipsEnabled=true +UnhideDelay=0 +ZoomEnabled=true +ZoomPercent=150 diff --git a/desktop/scripts/apply-desktop-profile.sh b/desktop/scripts/apply-desktop-profile.sh new file mode 100644 index 0000000..1fb84a1 --- /dev/null +++ b/desktop/scripts/apply-desktop-profile.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${HOME:=/home/node}" +: "${XDG_CONFIG_HOME:=$HOME/.config}" +: "${XDG_STATE_HOME:=$HOME/.local/state}" + +PROFILE_VERSION="v1" +PROFILE_ROOT="/opt/desktop" +MARKER_DIR="$XDG_STATE_HOME/microagent/desktop" +MARKER_FILE="$MARKER_DIR/desktop-${PROFILE_VERSION}.seeded" + +if [ -f "$MARKER_FILE" ]; then + exit 0 +fi + +mkdir -p "$MARKER_DIR" "$XDG_CONFIG_HOME" + +# XFCE config +rm -rf "$XDG_CONFIG_HOME/xfce4" +cp -R "$PROFILE_ROOT/xfce" "$XDG_CONFIG_HOME/xfce4" + +# Plank config +mkdir -p "$XDG_CONFIG_HOME/plank" +cp -R "$PROFILE_ROOT/plank/." "$XDG_CONFIG_HOME/plank/" + +touch "$MARKER_FILE" +echo "Applied desktop profile: ${PROFILE_VERSION}" diff --git a/desktop/xfce/terminal/terminalrc b/desktop/xfce/terminal/terminalrc new file mode 100644 index 0000000..a1fbcaf --- /dev/null +++ b/desktop/xfce/terminal/terminalrc @@ -0,0 +1,3 @@ +[Configuration] +FontName=DejaVu Sans Mono 11 +FontUseSystem=FALSE diff --git a/desktop/xfce/xfconf/xfce-perchannel-xml/xfce4-desktop.xml b/desktop/xfce/xfconf/xfce-perchannel-xml/xfce4-desktop.xml new file mode 100644 index 0000000..de5fe63 --- /dev/null +++ b/desktop/xfce/xfconf/xfce-perchannel-xml/xfce4-desktop.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/desktop/xfce/xfconf/xfce-perchannel-xml/xfce4-panel.xml b/desktop/xfce/xfconf/xfce-perchannel-xml/xfce4-panel.xml new file mode 100644 index 0000000..60e3c23 --- /dev/null +++ b/desktop/xfce/xfconf/xfce-perchannel-xml/xfce4-panel.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/desktop/xfce/xfconf/xfce-perchannel-xml/xfwm4.xml b/desktop/xfce/xfconf/xfce-perchannel-xml/xfwm4.xml new file mode 100644 index 0000000..d685c45 --- /dev/null +++ b/desktop/xfce/xfconf/xfce-perchannel-xml/xfwm4.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/desktop/xfce/xfconf/xfce-perchannel-xml/xsettings.xml b/desktop/xfce/xfconf/xfce-perchannel-xml/xsettings.xml new file mode 100644 index 0000000..3ee9248 --- /dev/null +++ b/desktop/xfce/xfconf/xfce-perchannel-xml/xsettings.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/microagent-desktop-session.sh b/microagent-desktop-session.sh index 992450c..2bb1aa5 100644 --- a/microagent-desktop-session.sh +++ b/microagent-desktop-session.sh @@ -2,6 +2,10 @@ set -uo pipefail export DISPLAY=:0 +export DESKTOP_SESSION=xfce +export XDG_CURRENT_DESKTOP=XFCE +export XDG_SESSION_DESKTOP=xfce +export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-/home/node/.config}" log() { printf '[microagent-desktop] %s\n' "$*" >&2 @@ -23,31 +27,38 @@ cleanup() { trap - INT TERM [ -n "${websockify_pid:-}" ] && kill "$websockify_pid" >/dev/null 2>&1 || true [ -n "${x11vnc_pid:-}" ] && kill "$x11vnc_pid" >/dev/null 2>&1 || true - [ -n "${xterm_pid:-}" ] && kill "$xterm_pid" >/dev/null 2>&1 || true - [ -n "${openbox_pid:-}" ] && kill "$openbox_pid" >/dev/null 2>&1 || true + [ -n "${plank_pid:-}" ] && kill "$plank_pid" >/dev/null 2>&1 || true + [ -n "${xfce_pid:-}" ] && kill "$xfce_pid" >/dev/null 2>&1 || true [ -n "${xvfb_pid:-}" ] && kill "$xvfb_pid" >/dev/null 2>&1 || true wait >/dev/null 2>&1 || true exit 0 } -start_openbox() { - reap_if_needed "${openbox_pid:-}" - log "starting openbox" - runuser -u node -- env DISPLAY="$DISPLAY" openbox >>/tmp/openbox.log 2>&1 & - openbox_pid=$! +start_xfce() { + reap_if_needed "${xfce_pid:-}" + log "starting xfce4-session" + runuser -u node -- env \ + DISPLAY="$DISPLAY" \ + DESKTOP_SESSION="$DESKTOP_SESSION" \ + XDG_CURRENT_DESKTOP="$XDG_CURRENT_DESKTOP" \ + XDG_SESSION_DESKTOP="$XDG_SESSION_DESKTOP" \ + XDG_CONFIG_HOME="$XDG_CONFIG_HOME" \ + dbus-launch --exit-with-session xfce4-session >>/tmp/xfce.log 2>&1 & + xfce_pid=$! } -start_xterm() { - reap_if_needed "${xterm_pid:-}" - log "starting xterm" - runuser -u node -- env DISPLAY="$DISPLAY" xterm -fa Monospace -fs 12 >>/tmp/xterm.log 2>&1 & - xterm_pid=$! +start_plank() { + reap_if_needed "${plank_pid:-}" + log "starting plank" + runuser -u node -- env DISPLAY="$DISPLAY" XDG_CONFIG_HOME="$XDG_CONFIG_HOME" \ + plank >>/tmp/plank.log 2>&1 & + plank_pid=$! } start_x11vnc() { reap_if_needed "${x11vnc_pid:-}" log "starting x11vnc" - x11vnc -display "$DISPLAY" -rfbport 5900 -forever -shared -nopw >>/tmp/x11vnc.log 2>&1 & + x11vnc -display "$DISPLAY" -rfbport 5900 -forever -shared -nopw -quiet >>/tmp/x11vnc.log 2>&1 & x11vnc_pid=$! } @@ -60,8 +71,13 @@ start_websockify() { trap cleanup INT TERM +# Apply desktop profile on first boot +log "applying desktop profile" +runuser -u node -- /opt/desktop/scripts/apply-desktop-profile.sh 2>&1 || true + +# Start Xvfb log "starting Xvfb" -Xvfb "$DISPLAY" -screen 0 1280x800x24 >/tmp/xvfb.log 2>&1 & +Xvfb "$DISPLAY" -screen 0 1280x800x24 -ac >/tmp/xvfb.log 2>&1 & xvfb_pid=$! ready=0 @@ -83,24 +99,37 @@ if [ "$ready" -ne 1 ]; then exit 1 fi -start_openbox -start_xterm +# Disable screensaver/DPMS +xset -display "$DISPLAY" -dpms s off s noblank >/dev/null 2>&1 || true + +# Start desktop stack +start_xfce +sleep 2 +start_plank start_x11vnc start_websockify +# Clipboard sync +if command -v autocutsel >/dev/null 2>&1; then + runuser -u node -- env DISPLAY="$DISPLAY" autocutsel -selection CLIPBOARD -fork >>/tmp/autocutsel.log 2>&1 || true + runuser -u node -- env DISPLAY="$DISPLAY" autocutsel -selection PRIMARY -fork >>/tmp/autocutsel.log 2>&1 || true +fi + +# Monitor and restart dead processes while true; do if ! pid_running "$xvfb_pid"; then log "Xvfb exited; stopping desktop session" wait "$xvfb_pid" >/dev/null 2>&1 || true exit 1 fi - if ! pid_running "${openbox_pid:-}"; then - log "openbox exited; restarting" - start_openbox + if ! pid_running "${xfce_pid:-}"; then + log "xfce4-session exited; restarting" + start_xfce + sleep 2 fi - if ! pid_running "${xterm_pid:-}"; then - log "xterm exited; restarting" - start_xterm + if ! pid_running "${plank_pid:-}"; then + log "plank exited; restarting" + start_plank fi if ! pid_running "${x11vnc_pid:-}"; then log "x11vnc exited; restarting" diff --git a/microagent-init.sh b/microagent-init.sh index 284a43e..bd3e164 100644 --- a/microagent-init.sh +++ b/microagent-init.sh @@ -96,6 +96,11 @@ if [ -f /etc/microagent/authorized_keys ]; then install -m 0600 -o node -g node /etc/microagent/authorized_keys /home/node/.ssh/authorized_keys fi +if [ -f /etc/microagent/trusted_user_ca_keys ]; then + log "using injected trusted user CA keys" + chmod 0644 /etc/microagent/trusted_user_ca_keys +fi + if command -v jitterentropy-rngd >/dev/null 2>&1; then log "starting jitterentropy-rngd" jitterentropy-rngd -v >/var/log/jitterentropy.log 2>&1 & diff --git a/sshd_config b/sshd_config index 27a7e83..caebe74 100644 --- a/sshd_config +++ b/sshd_config @@ -10,6 +10,7 @@ PasswordAuthentication no KbdInteractiveAuthentication no UsePAM no AuthorizedKeysFile .ssh/authorized_keys +TrustedUserCAKeys /etc/microagent/trusted_user_ca_keys StrictModes no SyslogFacility AUTH