name: mjdev-privilege-escalation
When a step needs root, pick the escalation method by environment — never assume an interactive
terminal exists (the Gradle daemon has no TTY, so a bare sudo would hang).
id -u == 0 or USER == root.DISPLAY or WAYLAND_DISPLAY set) and pkexec available:
use pkexec → it shows a graphical polkit authentication dialog (needs no TTY, works from
a detached daemon). This is the preferred desktop path.sudo (works with passwordless/NOPASSWD sudo on CI runners).pkexec resets the environment and detaches stdio — the child's stdout/stderr do NOT reach
the caller's console. If you need the output, have the privileged script tee to a log file
(e.g. exec > >(tee /tmp/x.log) 2>&1) and read that file afterwards.pkexec hands work back as root: chown results back to the invoking user via PKEXEC_UID
(or SUDO_UID under sudo) so files aren't left root-owned in the user's tree.makeIso and installDesktop (build.gradle.kts /
compositor.gradle.kts) choose root/pkexec/sudo exactly this way.val args = mutableListOf<String>()
val isRoot = System.getenv("USER") == "root" ||
runCatching { ProcessBuilder("id","-u").start().inputStream.bufferedReader().readText().trim() == "0" }.getOrDefault(false)
when {
isRoot -> {} // direct
File("/usr/bin/pkexec").canExecute() && !System.getenv("DISPLAY").isNullOrBlank() -> args += "pkexec"
else -> args += "sudo"
}
args += listOf("/bin/bash", scriptPath, /* … */)
ProcessBuilder(args).inheritIO().start().waitFor()
if [ "$(id -u)" -eq 0 ]; then SUDO=;
elif command -v pkexec >/dev/null && { [ -n "$DISPLAY" ] || [ -n "$WAYLAND_DISPLAY" ]; }; then SUDO=pkexec;
else SUDO=sudo; fi
"$SUDO" sh -c '…privileged…'