Skip to content

feat(nosudo): install tmux without sudo, and stop CI masking the gap - #56

Merged
YASoftwareDev merged 1 commit into
masterfrom
fix/nosudo-tmux
Sep 19, 2026
Merged

YASoftwareDev merged 1 commit into
masterfrom
fix/nosudo-tmux

Conversation

@YASoftwareDev

Copy link
Copy Markdown
Owner

What

A non-sudoer could install these dotfiles and end up with tmux config and tmux
plugins but no tmux binary. _install_tmux closes that, and the no-sudo CI
jobs stop pre-installing tmux so the path is actually exercised.

Why it existed, and why CI was never going to find it

Nothing in the no-sudo path installed tmux. The apt branch gets it from apt; the
no-apt branch only printed tmux not found - install it: <hint> - while the same
run went on to link .tmux.conf, link .tmux.conf.local and clone tmux plugins.

CI reported 15 green no-sudo cells throughout. Both no-sudo jobs and
Dockerfile.nosudo installed tmux as a root prerequisite, so has tmux was
true before install.sh ran. The test environment was supplying the thing under
test - a green that meant less than it appeared. Removing that prerequisite is the
actual mechanization here; the installer alone would have left the hole open for
the next tool.

Found on a real host (a fleet box where the operator's account is not in sudoers),
not by any check in this repo.

How

_install_tmux fetches the static AppImage from nelsonenzo/tmux-appimage. Two
things stated plainly rather than buried:

  • It is a third-party build. Upstream tmux publishes source only (checked: the
    latest release carries just tmux-<ver>.tar.gz), and building it needs libevent
    and ncurses built locally too, so there is no one-command official binary. The
    installer verifies the binary runs before linking it and logs where it came from.
  • FUSE is usually absent, so the direct AppImage run fails and
    --appimage-extract is what actually installs it. That is not a theoretical
    fallback: it is the path that fired in every container tested and on the host
    where this surfaced.

apt remains preferred; this runs only when CAN_APT=false. x86_64 only - other
arches get a warning naming the package manager instead.

Verified

Container with no sudo binary and no tmux, unprivileged user:

tmux absent: yes / sudo binary: absent / user: nosudoer uid=1000
tmux installed → ~/.local/bin/tmux (tmux 3.5a) [extracted, no FUSE]
PASS: tmux runs
PASS: started and killed a real session
PASS: second run skipped        # idempotent

Same result on almalinux:9 (the RHEL CAN_APT=false path).

Red-proof. The same probe against master fails, so it discriminates:

/probe.sh: line 20: _install_tmux: command not found
FAIL: ~/.local/bin/tmux is not executable

Repo gate for install-logic changes (CLAUDE.md requires this):

  • bash ci-local.sh --ubuntu 24.04 --profile nosudo-auto - PASS 1/1
  • bash ci-local.sh --alma 9 --profile nosudo-auto - PASS 1/1

And the green means what it claims - test.sh does check_cmd tmux and starts a
real session with the repo's own config, and inside the built image:

/home/user/.local/bin/tmux -> /home/user/.local/opt/squashfs-root/usr/bin/tmux
tmux 3.5a

Also: bash test.sh workstation 61/62, 0 failures, 1 skip (unchanged);
tests/lint-workflows.sh PASSED; tests/ci-gate-covers-all.py passes; shellcheck
clean.

Deliberately not in this PR

update.sh has no tmux entry, so an AppImage-installed tmux is not refreshed by
update.sh - re-running the install replaces it. Adding a tool entry touches the
arg parser and _KNOWN_TOOLS, which is a separate concern; saying so rather than
leaving it as a silent gap.

bat is missing from this repo in the same way. It is a feature rather than a
broken promise, so it is not folded in here.

This repo ships .tmux.conf, .tmux.conf.local and clones tmux plugins, so a
host with the configs and no tmux binary is incoherent. That is what a
non-sudoer got: nothing in the no-sudo path ever installed tmux. Found on a
real fleet host, not in CI.

_install_tmux fetches the static AppImage (nelsonenzo/tmux-appimage - third
party, because upstream publishes source only) and falls back to
--appimage-extract where FUSE is absent. That fallback is not theoretical:
it is the path that fires in containers and on the host where this surfaced.
apt is still preferred; this runs only when CAN_APT=false.

CI could not have caught it. Both no-sudo jobs and Dockerfile.nosudo
pre-installed tmux as a root prerequisite, so `has tmux` was true before
install.sh ran and 15 green cells said nothing about the missing installer -
the environment was supplying the thing under test. Those prerequisites are
removed, so the install path must now provide tmux and test.sh must find it.

Verified: no-sudo container with no sudo binary and no tmux installs 3.5a via
the extract path, starts a real session, and a second run skips; same on
almalinux:9. Red-proofed against master, where the probe fails with
_install_tmux: command not found. ci-local.sh nosudo-auto passes on both
ubuntu:24.04 and alma 9, and inside the built image tmux resolves to
~/.local/bin/tmux -> ~/.local/opt/squashfs-root/usr/bin/tmux.
@YASoftwareDev
YASoftwareDev merged commit d56004c into master Sep 19, 2026
30 checks passed
@YASoftwareDev
YASoftwareDev deleted the fix/nosudo-tmux branch September 19, 2026 19:03
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.

2 participants