Compare commits

...
Author SHA1 Message Date
iris
cce85a6c1b fix(#540): use systemd.globalEnvironment instead of environment.variables
environment.variables writes to /etc/environment (PAM sessions only)
and is not visible to systemd service units. The correct path for
env vars that need to reach all systemd services is
systemd.globalEnvironment (sets DefaultEnvironment in systemd.conf),
which is the pattern established by #608 for HYPERHIVE_STATE_DIR.

Also update the inline comment reference from environment.variables
to systemd.globalEnvironment.
2026-05-31 22:59:46 +02:00
iris
8a97277f20 fix(#540): pin weston socket + inject WAYLAND_DISPLAY globally
Services started by systemd in a gui-enabled container didn't have
WAYLAND_DISPLAY set, so Wayland clients couldn't find the compositor.
libwayland would fall back to a headless display or error out, leaving
apps running invisibly while the VNC session showed a blank weston
desktop (the double-screen problem).

Fix in weston-vnc.nix:
- Pass --socket=wayland-0 to weston so the socket name is
  deterministic (weston normally picks any free wayland-N name).
- Set WAYLAND_DISPLAY=wayland-0 and XDG_RUNTIME_DIR=/run/user/0 as
  global environment.variables gated on hyperhive.gui.enable, so
  every service in the container inherits them automatically.
- Update gui.json to include wayland_display for tooling that reads it.

Update docs/gotchas.md with the rationale and pointer to #540.
2026-05-31 22:59:46 +02:00
2 changed files with 42 additions and 4 deletions

View file

@ -264,9 +264,19 @@ connects to the compositor at `127.0.0.1:<vnc_port>`.
`[15900, 16799]`. Mirrors the agent web-UI port pattern from
`docs/gotchas.md::Web UI ports collide on hash` — same FNV-1a
constant, different range. The compositor's startup script writes
`/etc/hyperhive/gui.json = {"vnc_port":N,"auth":"none"}` so the
harness reads the port at runtime; no nix-side / harness-side hash
`/etc/hyperhive/gui.json = {"vnc_port":N,"auth":"none","wayland_display":"wayland-0"}`
so the harness reads the port at runtime; no nix-side / harness-side hash
duplication.
- **Fixed Wayland socket name (`--socket=wayland-0`)**: weston is
launched with `--socket=wayland-0` so the socket path is
deterministic. `harness-base.nix` exports `WAYLAND_DISPLAY=wayland-0`
and `XDG_RUNTIME_DIR=/run/user/0` as global system environment
variables (gated on `hyperhive.gui.enable`) so every systemd service
in the container inherits them. Without this, services starting
Wayland clients could not find the compositor — libwayland falls
back to a headless display or errors out, the app "works" on a
second invisible display, and the VNC session shows a blank weston
desktop (#540 double-screen).
- **VNC bind address**: weston's VNC backend has no CLI
bind-address flag (unlike the RDP backend's `--address`), so the
listener binds `0.0.0.0`. The harness relay only connects via

View file

@ -78,9 +78,11 @@
done
VNC_PORT=$((15900 + hash % 900))
# Marker file the harness reads at startup.
# Marker file the harness reads at startup. Also records the
# fixed Wayland socket name (`wayland-0`) so other tooling can
# read it without inspecting the env-var injection below.
${pkgs.coreutils}/bin/mkdir -p /etc/hyperhive
${pkgs.coreutils}/bin/printf '{"vnc_port":%d,"auth":"none"}\n' \
${pkgs.coreutils}/bin/printf '{"vnc_port":%d,"auth":"none","wayland_display":"wayland-0"}\n' \
"$VNC_PORT" > /etc/hyperhive/gui.json || true
# --disable-transport-layer-security: skips the VeNCrypt TLS
@ -90,11 +92,21 @@
WESTON_INI=$(${pkgs.coreutils}/bin/mktemp /tmp/weston-XXXXXX.ini)
${pkgs.coreutils}/bin/printf '[core]\nidle-time=0\n\n[vnc]\nauth-method=none\n' > "$WESTON_INI"
# --socket=wayland-0: pin the compositor's Wayland socket name
# to `wayland-0` (weston default is to pick any free name such
# as `wayland-1`). Pinning lets the WAYLAND_DISPLAY=wayland-0
# global env injection below (see systemd.globalEnvironment) take
# effect unconditionally — any Wayland client launched by any
# systemd service in this container automatically connects to
# this compositor instead of failing or starting a second
# isolated display. Closes #540 (double-screen: VNC shows blank
# weston desktop while services render on a different seat).
exec ${pkgs.weston}/bin/weston \
--config="$WESTON_INI" \
--backend=vnc-backend.so \
--renderer=pixman \
--port="$VNC_PORT" \
--socket=wayland-0 \
--disable-transport-layer-security
'';
Restart = "on-failure";
@ -102,6 +114,22 @@
};
};
# Expose the compositor's socket to every systemd service in the
# container so Wayland clients (e.g. bitburner started via
# `systemd.services.*` in agent.nix) can find the compositor
# without per-service wiring. `systemd.globalEnvironment` is the
# correct path (established by #608 for HYPERHIVE_STATE_DIR) —
# it sets DefaultEnvironment in systemd.conf, reaching all units
# started by PID 1. `environment.variables` goes to /etc/environment
# (PAM sessions only) and is NOT visible to systemd service units.
# Without these vars a service starting a Wayland client would either
# fail to connect (libwayland falls back to a headless display) or
# open a second compositor — VNC shows a blank desktop (#540).
systemd.globalEnvironment = {
WAYLAND_DISPLAY = "wayland-0";
XDG_RUNTIME_DIR = "/run/user/0";
};
# weston on the agent's interactive PATH so claude can run Wayland
# clients / weston-info against the compositor.
environment.systemPackages = [ pkgs.weston ];