Skip to content

fix: separate the desktop user from the user running the install - #26

Merged
catinspace-au merged 1 commit into
mainfrom
fix/desktop-user-separation-and-rdp-watchdog
Aug 3, 2026
Merged

fix: separate the desktop user from the user running the install#26
catinspace-au merged 1 commit into
mainfrom
fix/desktop-user-separation-and-rdp-watchdog

Conversation

@catinspace-au

Copy link
Copy Markdown
Contributor

The playbook assumed the desktop user and the user running the install are the
same person. On the devex desktop VMs they are not - hyperi-infra connects as
ubuntu while the desktop belongs to hyperi - so everything user-scoped
either landed in the wrong home or failed outright. All of this came out of
running the remediation against dragonfly, kaz and kay for real.

The worst of it made a tombstone lie:

[WARNING]: Insufficient permissions to access /home/hyperi/.cargo/bin/uv.
           Treating as absent
ok: [target] => (item=uv)

become: false means the CONNECTING user, so as ubuntu the file module could
not read /home/hyperi and called the file absent. Green tombstone, and the
retired uv still sitting there shadowing the real install on PATH. The molecule
verify agreed, because it stat'ed the service account's empty home. A host that
was never fixed looked clean twice over.

Rather than keep patching sites, we audited every task combining become: false with user_home - 19 of them, 8 genuinely wrong, the rest macOS-only
where Homebrew refuses to run as root and the two users cannot differ. Two of
the eight paired become: false with become_user:, which does nothing:
become_user is ignored while become is false, and it reads as correct in
review.

The knob is now -e hyperi_target_user=<name> rather than overriding an
internal fact. Molecule verify takes MOLECULE_TARGET_DESKTOP_USER (it accepts
no extra arguments) and prints which user it checked, so a run against the
wrong home is visible instead of quietly green.

Also in here:

  • Docker Desktop's context. The uninstall does not take it - context state
    is a per-user file under ~/.docker/contexts. On kay desktop-linux was
    also the SELECTED context, so every docker command failed against a socket
    that no longer exists. Docker was simply broken for her.

  • hyperi-update was dead on Ubuntu 26.04. It gated on sudo -v, and 25.10+
    ships sudo-rs, whose -v demands interactive auth even where NOPASSWD grants
    the commands. It aborted before doing anything, on every 26.04 box and under
    every unattended caller - which is what --yes exists for. It also did not
    wait for the dpkg lock, so an unattended-upgrades run in progress made the
    upgrade exit 100 while everything else reported success.

  • An RDP watchdog. Force-stopping another session from the RDP login screen
    makes gdm tear down that session and the in-flight RDP login with it, and
    leaves the system daemon accepting TCP on 3389 while servicing nothing. Every
    later connection is a blank screen and the daemon does not log so much as an
    incoming connection. Restarting gdm does NOT clear it; only restarting
    gnome-remote-desktop does - which on a headless host needs ssh that may not
    exist.

    It matches gdm's failure line rather than probing the port. We built the
    probe first and it worked, then noticed it makes the daemon build and tear
    down a session - the same path that wedges it. A health check that can cause
    the fault is not a health check. Gated on the presence of the GNOME handover
    unit, which is the mechanism the fault lives in, rather than on a version
    number.

Done when: the three real hosts converge clean, the removals actually land, and
they hold across a reboot.

Verified on dragonfly, desktop-kaz and desktop-kay, not just in check mode:

  • converge failed=0 on each, then updated and rebooted
  • molecule verify green on all three against the RIGHT user
  • kay: desktop-linux gone and docker ps works again; ~/.cargo/bin/uv gone
    for real this time
  • kaz: confirmed by his own RDP login - handover daemon started, H264
    negotiated, clipboard and audio up
  • watchdog active and enabled on all three, deployed with --tags handover-watchdog so it could not restart the RDP daemon under anyone
  • watchdog proven end to end on dragonfly against a real journal and the real
    marker text, pointed at a throwaway target so it could not drop a live
    session

Not covered: gdm killing the in-flight login in the first place is upstream,
and the watchdog only catches that one marker.

The playbook assumed the two were the same. On a fleet machine they are not:
hyperi-infra's inventory connects as `ubuntu` while the desktop belongs to
`hyperi`, and everything user-scoped landed in the wrong home or failed
outright.

`-e hyperi_target_user=<name>` names the desktop user; `actual_user` and
`user_home` derive from it. Molecule verify takes it as
MOLECULE_TARGET_DESKTOP_USER, since `molecule verify` accepts no extra
arguments, and now prints which user it checked -- a run against the wrong home
was previously indistinguishable from a clean one.

`become: false` means the CONNECTING user, so every user-scoped task carrying
it was acting on the wrong account. An audit of tasks combining `become: false`
with `user_home` found 19, of which 8 were wrong; the rest are macOS-only,
where Homebrew refuses to run as root and the two users cannot differ. Two of
the eight paired `become: false` with `become_user:`, which does nothing --
`become_user` is ignored while `become` is false.

The worst of them made a tombstone lie. `ansible.builtin.file` cannot read a
path it has no permission for and reports "Insufficient permissions ...
Treating as absent", so the retired `~/.cargo/bin/uv` was reported removed
while it sat there shadowing the real install on PATH. The molecule verify
agreed, because it stat'ed the service account's empty home.

Also removes the Docker Desktop context, which the package uninstall leaves
behind: context state is a per-user file under ~/.docker/contexts, not package
state. Where `desktop-linux` was also the selected context every docker command
failed against a socket that no longer exists.

Two hyperi-update fixes, both of which made it a no-op where it mattered most:

- It gated on `sudo -v`, and Ubuntu 25.10+ ships sudo-rs, whose `-v` demands
  interactive authentication even where NOPASSWD grants the commands. It
  aborted before doing anything on every 26.04 box and under every unattended
  caller, which is what --yes exists for. Probes with `sudo -n true` now.
- It did not wait for the dpkg lock, so an unattended-upgrades run in progress
  made the upgrade exit 100 while everything else reported success -- a box
  that looks updated and is not.

Adds a watchdog to the rdp-server role for a fault that makes a remote-desktop
host permanently unreachable. Force-stopping another session from the RDP login
screen makes gdm tear down that session and the in-flight RDP login with it,
and leaves the system daemon accepting TCP on 3389 while servicing nothing --
later connections get a blank screen and the daemon does not log so much as an
incoming connection. Restarting gdm does not clear it; only restarting
gnome-remote-desktop does, which on a headless host needs ssh that may not
exist.

The watchdog matches gdm's own failure line rather than probing the port:
telling a wedged daemon from a healthy one over the wire needs a real RDP
connection, and an aborted one exercises the same session teardown that wedges
it, so a probe risks causing the fault it watches for. Gated on the presence of
the GNOME handover unit, which is the mechanism the fault lives in, rather than
on a version number.
@catinspace-au
catinspace-au merged commit 56cfb80 into main Aug 3, 2026
15 checks passed
@catinspace-au
catinspace-au deleted the fix/desktop-user-separation-and-rdp-watchdog branch August 3, 2026 04:51
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant