Merge upstream sync b86d4505 (README resolved toward CN rewrite)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QKxGW1raAWaqeU8WdHsMsp
This commit is contained in:
@@ -9,10 +9,12 @@
|
|||||||
# no prompt. lazydocker needs the root-owned Docker socket, so when the group is
|
# no prompt. lazydocker needs the root-owned Docker socket, so when the group is
|
||||||
# absent, gate that access behind a polkit prompt. If the user has opted into
|
# absent, gate that access behind a polkit prompt. If the user has opted into
|
||||||
# sudoless Docker (omarchy-setup-security-sudoless-docker), the socket is already
|
# sudoless Docker (omarchy-setup-security-sudoless-docker), the socket is already
|
||||||
# reachable, so run lazydocker directly. pkexec sanitizes the environment, so
|
# reachable, so run lazydocker directly — omarchy-sudo-docker answers that for
|
||||||
# carry TERM through for the TUI to render and run lazydocker from root's PATH.
|
# this session, so the prompt stays until the reboot that grants the group.
|
||||||
if id -nG 2>/dev/null | grep -qw docker; then
|
# pkexec sanitizes the environment, so carry TERM through for the TUI to render
|
||||||
exec lazydocker
|
# and run lazydocker from root's PATH.
|
||||||
else
|
if omarchy-sudo-docker; then
|
||||||
exec pkexec /usr/bin/env TERM="${TERM:-xterm-256color}" lazydocker
|
exec pkexec /usr/bin/env TERM="${TERM:-xterm-256color}" lazydocker
|
||||||
|
else
|
||||||
|
exec lazydocker
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -5,7 +5,10 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if ! id -nG "$USER" 2>/dev/null | grep -qw docker; then
|
# Ask about the configured groups, not this session's: right after enabling,
|
||||||
|
# sudoless Docker is on for the account even though the running session still
|
||||||
|
# needs a prompt, and this command is what turns it back off.
|
||||||
|
if omarchy-sudo-docker --configured; then
|
||||||
echo "Sudoless Docker is not enabled: $USER is not in the docker group."
|
echo "Sudoless Docker is not enabled: $USER is not in the docker group."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -13,13 +16,19 @@ fi
|
|||||||
echo "Removing $USER from the docker group..."
|
echo "Removing $USER from the docker group..."
|
||||||
sudo gpasswd -d "$USER" docker >/dev/null
|
sudo gpasswd -d "$USER" docker >/dev/null
|
||||||
|
|
||||||
# Group membership is fixed at login, so the running session keeps its docker
|
# Group membership is only re-read by a fresh session, and in practice logging
|
||||||
# access until it ends. Flag a reboot so omarchy-update-restart prompts for one
|
# out or newgrp isn't enough — only a reboot reliably applies it. Record it so a
|
||||||
# (and the bar shows it pending); a plain log out and back in works too.
|
# later `omarchy update` still prompts (omarchy-update-restart reads this), then
|
||||||
|
# offer to do it now.
|
||||||
omarchy-state set reboot-required
|
omarchy-state set reboot-required
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Sudoless Docker DISABLED. Reboot (or log out and back in) for the change to take effect."
|
echo "Sudoless Docker DISABLED. Docker access goes through a polkit/sudo prompt"
|
||||||
echo "Docker access now goes through a polkit/sudo prompt again: the Docker TUI"
|
echo "again: the Docker TUI (Super + Shift + D) and the Windows VM ask when they"
|
||||||
echo "(Super + Shift + D) and the Windows VM will ask when they need it, and the"
|
echo "need it, and the plain 'docker' CLI runs under sudo. It takes effect after a reboot."
|
||||||
echo "plain 'docker' CLI runs under sudo."
|
echo ""
|
||||||
|
# The migration reuses this command during 'omarchy update' and defers the
|
||||||
|
# reboot to omarchy-update-restart, so it doesn't cut the update short.
|
||||||
|
if [[ -z ${OMARCHY_DEFER_REBOOT:-} ]] && gum confirm "Reboot now to apply?"; then
|
||||||
|
omarchy-system-reboot
|
||||||
|
fi
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if id -nG "$USER" 2>/dev/null | grep -qw docker; then
|
# Ask about the configured groups, not this session's: once enabled it stays
|
||||||
|
# enabled for the account even before the reboot that lets this session use it.
|
||||||
|
if ! omarchy-sudo-docker --configured; then
|
||||||
echo "Sudoless Docker is already enabled: $USER is in the docker group."
|
echo "Sudoless Docker is already enabled: $USER is in the docker group."
|
||||||
echo "To disable it again, run: omarchy-remove-security-sudoless-docker"
|
echo "To disable it again, run: omarchy-remove-security-sudoless-docker"
|
||||||
exit 0
|
exit 0
|
||||||
@@ -28,14 +30,20 @@ echo ""
|
|||||||
|
|
||||||
if gum confirm "Enable sudoless Docker? This gives anything running as you passwordless root."; then
|
if gum confirm "Enable sudoless Docker? This gives anything running as you passwordless root."; then
|
||||||
sudo usermod -aG docker "$USER"
|
sudo usermod -aG docker "$USER"
|
||||||
# Group membership is fixed at login, so docker won't be reachable without a
|
# A new docker group membership is only picked up by a fresh session, and in
|
||||||
# prompt until the session restarts. Flag a reboot so omarchy-update-restart
|
# practice logging out or newgrp isn't enough — only a reboot reliably applies
|
||||||
# prompts for one (and the bar shows it pending).
|
# it. Record it so a later `omarchy update` still prompts
|
||||||
|
# (omarchy-update-restart reads this), then offer to do it now.
|
||||||
omarchy-state set reboot-required
|
omarchy-state set reboot-required
|
||||||
echo ""
|
echo ""
|
||||||
echo "Sudoless Docker ENABLED. Reboot, or log out and back in (or run 'newgrp docker'),"
|
echo "Sudoless Docker ENABLED. It takes effect after a reboot."
|
||||||
echo "for the new group membership to take effect."
|
echo "To disable it again: Setup > Security > Sudoless Docker."
|
||||||
echo "To disable it again, run: omarchy-remove-security-sudoless-docker"
|
echo ""
|
||||||
|
# The migration reuses this command during 'omarchy update' and defers the
|
||||||
|
# reboot to omarchy-update-restart, so it doesn't cut the update short.
|
||||||
|
if [[ -z ${OMARCHY_DEFER_REBOOT:-} ]] && gum confirm "Reboot now to apply?"; then
|
||||||
|
omarchy-system-reboot
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "Aborted. No changes made. Docker access still goes through a prompt."
|
echo "Aborted. No changes made. Docker access still goes through a prompt."
|
||||||
fi
|
fi
|
||||||
|
|||||||
Executable
+44
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Succeed when Docker needs sudo, fail when it can be used directly
|
||||||
|
# omarchy:args=[--configured]
|
||||||
|
# omarchy:examples=omarchy-sudo-docker && echo "needs sudo" | omarchy-sudo-docker --configured
|
||||||
|
# omarchy:hidden=true
|
||||||
|
|
||||||
|
# The docker group is root-equivalent, so Omarchy leaves users out of it by
|
||||||
|
# default and reaches the daemon through a prompt instead. Everything that has
|
||||||
|
# to make that choice asks here rather than testing group membership itself.
|
||||||
|
#
|
||||||
|
# Two questions, because they have different answers between toggling sudoless
|
||||||
|
# Docker and the reboot that applies it (group membership is fixed when the
|
||||||
|
# session is created):
|
||||||
|
#
|
||||||
|
# (default) Does Docker need sudo *right now*? Answered by whether this
|
||||||
|
# process can actually reach the socket, which is what decides
|
||||||
|
# if a command must elevate. Still true in the window after
|
||||||
|
# sudoless Docker is enabled but before the reboot.
|
||||||
|
# --configured Will it need sudo once the account's groups take effect?
|
||||||
|
# Answered from the account's configured groups, so the menu
|
||||||
|
# offers the toggle that can actually change state.
|
||||||
|
#
|
||||||
|
# Succeeds (exit 0) when sudo is needed, so it reads as `if omarchy-sudo-docker`.
|
||||||
|
|
||||||
|
DOCKER_SOCKET="${OMARCHY_DOCKER_SOCKET:-/var/run/docker.sock}"
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
--configured)
|
||||||
|
# An account in the docker group will not need sudo after the next login.
|
||||||
|
id -nG "$USER" 2>/dev/null | grep -qw docker && exit 1
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
"")
|
||||||
|
# A socket we can write is a daemon we can drive without elevating. A missing
|
||||||
|
# socket counts as needing sudo: reaching it means starting it as root anyway.
|
||||||
|
[[ -w $DOCKER_SOCKET ]] && exit 1
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: omarchy-sudo-docker [--configured]" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -31,8 +31,11 @@ CONTAINER="omarchy-windows"
|
|||||||
|
|
||||||
# --- privilege helpers -------------------------------------------------------
|
# --- privilege helpers -------------------------------------------------------
|
||||||
|
|
||||||
# True when the user can reach the Docker socket directly (sudoless Docker on).
|
# True when this session can reach the Docker socket directly (sudoless Docker
|
||||||
in_docker_group() { id -nG 2>/dev/null | grep -qw docker; }
|
# on and in effect). Asking about the socket rather than the configured groups
|
||||||
|
# keeps the prompt in place through the window where sudoless Docker is enabled
|
||||||
|
# but the reboot that grants the group has not happened yet.
|
||||||
|
docker_needs_sudo() { omarchy-sudo-docker; }
|
||||||
|
|
||||||
# The command to hand pkexec for the privileged re-exec. pkexec runs whatever
|
# The command to hand pkexec for the privileged re-exec. pkexec runs whatever
|
||||||
# executable it is given (after authorization) and only shows the path in the
|
# executable it is given (after authorization) and only shows the path in the
|
||||||
@@ -64,7 +67,7 @@ priv_target() {
|
|||||||
priv() {
|
priv() {
|
||||||
local action="$1"
|
local action="$1"
|
||||||
shift
|
shift
|
||||||
if [[ $action != write_compose ]] && in_docker_group; then
|
if [[ $action != write_compose ]] && ! docker_needs_sudo; then
|
||||||
"__priv_$action" "$@"
|
"__priv_$action" "$@"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -179,7 +179,7 @@
|
|||||||
"setup.security.fido2": {"icon":"","label":"Fido2","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-fido2"},
|
"setup.security.fido2": {"icon":"","label":"Fido2","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-fido2"},
|
||||||
"setup.security.sshd": {"icon":"","label":"SSHD","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-sshd"},
|
"setup.security.sshd": {"icon":"","label":"SSHD","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-sshd"},
|
||||||
"setup.security.passwordless-sudo": {"icon":"","label":"Passwordless Sudo","action":"omarchy-launch-floating-terminal-with-presentation omarchy-sudo-passwordless"},
|
"setup.security.passwordless-sudo": {"icon":"","label":"Passwordless Sudo","action":"omarchy-launch-floating-terminal-with-presentation omarchy-sudo-passwordless"},
|
||||||
"setup.security.sudoless-docker": {"icon":"","label":"Sudoless Docker","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-sudoless-docker"},
|
"setup.security.sudoless-docker": {"icon":"","label":"Sudoless Docker","when":"omarchy-sudo-docker --configured","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-sudoless-docker"},
|
||||||
"setup.config.hyprland": {"icon":"","label":"Hyprland","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/hyprland.lua\""},
|
"setup.config.hyprland": {"icon":"","label":"Hyprland","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/hyprland.lua\""},
|
||||||
"setup.config.hyprsunset": {"icon":"","label":"Hyprsunset","action":"omarchy-launch-config-editor ~/.config/hypr/hyprsunset.conf && omarchy-restart-hyprsunset"},
|
"setup.config.hyprsunset": {"icon":"","label":"Hyprsunset","action":"omarchy-launch-config-editor ~/.config/hypr/hyprsunset.conf && omarchy-restart-hyprsunset"},
|
||||||
"setup.config.xcompose": {"icon":"","label":"XCompose","action":"omarchy-launch-config-editor ~/.XCompose && omarchy-restart-xcompose"},
|
"setup.config.xcompose": {"icon":"","label":"XCompose","action":"omarchy-launch-config-editor ~/.XCompose && omarchy-restart-xcompose"},
|
||||||
@@ -291,7 +291,7 @@
|
|||||||
"remove.security.fingerprint": {"icon":"","label":"Fingerprint","when":"omarchy-pkg-present fprintd","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-fingerprint"},
|
"remove.security.fingerprint": {"icon":"","label":"Fingerprint","when":"omarchy-pkg-present fprintd","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-fingerprint"},
|
||||||
"remove.security.fido2": {"icon":"","label":"Fido2","when":"omarchy-pkg-present pam-u2f","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-fido2"},
|
"remove.security.fido2": {"icon":"","label":"Fido2","when":"omarchy-pkg-present pam-u2f","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-fido2"},
|
||||||
"remove.security.sshd": {"icon":"","label":"SSHD","when":"systemctl is-enabled --quiet sshd","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-sshd"},
|
"remove.security.sshd": {"icon":"","label":"SSHD","when":"systemctl is-enabled --quiet sshd","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-sshd"},
|
||||||
"remove.security.sudoless-docker": {"icon":"","label":"Sudoless Docker","when":"id -nG | grep -qw docker","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-sudoless-docker"},
|
"remove.security.sudoless-docker": {"icon":"","label":"Sudoless Docker","when":"! omarchy-sudo-docker --configured","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-security-sudoless-docker"},
|
||||||
"remove.browser.chrome": {"icon":"","label":"Chrome","when":"omarchy-pkg-present google-chrome","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-remove-browser chrome'"},
|
"remove.browser.chrome": {"icon":"","label":"Chrome","when":"omarchy-pkg-present google-chrome","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-remove-browser chrome'"},
|
||||||
"remove.browser.edge": {"icon":"","label":"Edge","when":"omarchy-pkg-present microsoft-edge-stable-bin","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-remove-browser edge'"},
|
"remove.browser.edge": {"icon":"","label":"Edge","when":"omarchy-pkg-present microsoft-edge-stable-bin","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-remove-browser edge'"},
|
||||||
"remove.browser.brave": {"icon":"","label":"Brave","when":"omarchy-pkg-present brave-bin","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-remove-browser brave'"},
|
"remove.browser.brave": {"icon":"","label":"Brave","when":"omarchy-pkg-present brave-bin","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-remove-browser brave'"},
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ echo "Move this install to the opt-in docker group default (the group is root-eq
|
|||||||
|
|
||||||
# The docker group grants passwordless root (a container can bind-mount / and
|
# The docker group grants passwordless root (a container can bind-mount / and
|
||||||
# rewrite the host), so Omarchy no longer puts users in it by default. Bring
|
# rewrite the host), so Omarchy no longer puts users in it by default. Bring
|
||||||
# existing installs in line: remove this user from the group if present. It takes
|
# existing installs in line: remove this user from the group if present. The
|
||||||
# effect at next login, and the current session keeps working until then. Anyone
|
# change applies after a reboot, so it stays reachable until then. Anyone who
|
||||||
# who wants passwordless docker back can opt in, behind a warning, with
|
# wants passwordless docker back can opt in, behind a warning, with
|
||||||
# Setup > Security > Sudoless Docker. Reuses the removal command so there is one
|
# Setup > Security > Sudoless Docker. Reuses the removal command so there is one
|
||||||
# source of truth for the privileged change and its notice.
|
# source of truth for the privileged change and its notice; DEFER_REBOOT keeps
|
||||||
|
# it from prompting mid-update — omarchy-update-restart handles the reboot once
|
||||||
|
# the whole update has finished.
|
||||||
if id -nG "$USER" | grep -qw docker; then
|
if id -nG "$USER" | grep -qw docker; then
|
||||||
omarchy-remove-security-sudoless-docker
|
OMARCHY_DEFER_REBOOT=1 omarchy-remove-security-sudoless-docker
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# The Docker app entry copied into ~/.local/share/applications used to run
|
# The Docker app entry copied into ~/.local/share/applications used to run
|
||||||
|
|||||||
@@ -39,16 +39,30 @@ cat >"$stub_bin/gpasswd" <<'STUB'
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
echo "$@" >>"${GPASSWD_CALLS:?}"
|
echo "$@" >>"${GPASSWD_CALLS:?}"
|
||||||
STUB
|
STUB
|
||||||
chmod +x "$stub_bin/id" "$stub_bin/sudo" "$stub_bin/gpasswd"
|
# gum confirm always says yes, and reboot records that it fired: the migration
|
||||||
|
# must still NOT reboot (it defers to omarchy-update-restart), so neither should
|
||||||
|
# be reached.
|
||||||
|
cat >"$stub_bin/gum" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
[[ $1 == confirm ]] && exit 0
|
||||||
|
exit 0
|
||||||
|
STUB
|
||||||
|
cat >"$stub_bin/omarchy-system-reboot" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
touch "${REBOOT_CALLED:?}"
|
||||||
|
STUB
|
||||||
|
chmod +x "$stub_bin/id" "$stub_bin/sudo" "$stub_bin/gpasswd" "$stub_bin/gum" "$stub_bin/omarchy-system-reboot"
|
||||||
|
|
||||||
reboot_flag="$home/.local/state/omarchy/reboot-required"
|
reboot_flag="$home/.local/state/omarchy/reboot-required"
|
||||||
gpasswd_calls="$test_dir/gpasswd-calls"
|
gpasswd_calls="$test_dir/gpasswd-calls"
|
||||||
|
reboot_called="$test_dir/reboot-called"
|
||||||
launcher="$home/.local/share/applications/Docker.desktop"
|
launcher="$home/.local/share/applications/Docker.desktop"
|
||||||
|
|
||||||
run_migration() {
|
run_migration() {
|
||||||
rm -f "$gpasswd_calls" "$reboot_flag"
|
rm -f "$gpasswd_calls" "$reboot_flag" "$reboot_called"
|
||||||
HOME="$home" OMARCHY_PATH="$omarchy_path" USER="tester" STUB_GROUPS="$1" \
|
HOME="$home" OMARCHY_PATH="$omarchy_path" USER="tester" STUB_GROUPS="$1" \
|
||||||
GPASSWD_CALLS="$gpasswd_calls" PATH="$stub_bin:$ROOT/bin:$PATH" \
|
GPASSWD_CALLS="$gpasswd_calls" REBOOT_CALLED="$reboot_called" \
|
||||||
|
PATH="$stub_bin:$ROOT/bin:$PATH" \
|
||||||
bash -euo pipefail "$migration" >/dev/null 2>&1
|
bash -euo pipefail "$migration" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,6 +70,7 @@ run_migration() {
|
|||||||
run_migration "wheel input docker" || fail "migration runs when the user is in the docker group"
|
run_migration "wheel input docker" || fail "migration runs when the user is in the docker group"
|
||||||
grep -q -- "-d tester docker" "$gpasswd_calls" || fail "migration removes the user from the docker group"
|
grep -q -- "-d tester docker" "$gpasswd_calls" || fail "migration removes the user from the docker group"
|
||||||
[[ -f $reboot_flag ]] || fail "migration flags a reboot so the group change takes effect"
|
[[ -f $reboot_flag ]] || fail "migration flags a reboot so the group change takes effect"
|
||||||
|
[[ ! -f $reboot_called ]] || fail "migration must defer the reboot (not reboot mid-update)"
|
||||||
[[ $(cat "$launcher") == "NEW-LAUNCHER" ]] || fail "migration refreshes the stale Docker launcher entry"
|
[[ $(cat "$launcher") == "NEW-LAUNCHER" ]] || fail "migration refreshes the stale Docker launcher entry"
|
||||||
pass "migration removes the group, flags a reboot, and refreshes the launcher"
|
pass "migration removes the group, flags a reboot, and refreshes the launcher"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# omarchy-sudo-docker is the single answer to "does Docker need sudo", and it
|
||||||
|
# answers two different questions on purpose. The default asks whether this
|
||||||
|
# session can reach the socket, which is what decides if a command must elevate.
|
||||||
|
# --configured asks whether the account is set up for sudoless Docker, which is
|
||||||
|
# what the menu needs so it offers the toggle that can change state. Between
|
||||||
|
# enabling sudoless Docker and the reboot that grants the group, those disagree.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||||
|
|
||||||
|
TMPDIR=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$TMPDIR"' EXIT
|
||||||
|
|
||||||
|
command="$ROOT/bin/omarchy-sudo-docker"
|
||||||
|
|
||||||
|
# Stub id so the configured groups are controllable.
|
||||||
|
mkdir -p "$TMPDIR/bin"
|
||||||
|
cat >"$TMPDIR/bin/id" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
printf '%s\n' "${STUB_GROUPS:-wheel input}"
|
||||||
|
STUB
|
||||||
|
chmod +x "$TMPDIR/bin/id"
|
||||||
|
|
||||||
|
# A writable stand-in means the socket is reachable; an unwritable one means it
|
||||||
|
# is not. Test the file mode rather than a live daemon.
|
||||||
|
reachable_socket="$TMPDIR/reachable.sock"
|
||||||
|
blocked_socket="$TMPDIR/blocked.sock"
|
||||||
|
touch "$reachable_socket" "$blocked_socket"
|
||||||
|
chmod 600 "$reachable_socket"
|
||||||
|
chmod 400 "$blocked_socket"
|
||||||
|
|
||||||
|
run() { # SOCKET GROUPS [--configured]
|
||||||
|
env PATH="$TMPDIR/bin:$PATH" OMARCHY_DOCKER_SOCKET="$1" STUB_GROUPS="$2" USER=tester \
|
||||||
|
bash "$command" ${3:+"$3"}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default mode follows the socket, not the group list.
|
||||||
|
run "$blocked_socket" "wheel input" || fail "an unreachable socket means Docker needs sudo"
|
||||||
|
run "$reachable_socket" "wheel input" && fail "a reachable socket means Docker does not need sudo"
|
||||||
|
pass "default mode answers from the socket this session can reach"
|
||||||
|
|
||||||
|
# A socket that isn't there at all still needs elevation (starting it is root work).
|
||||||
|
run "$TMPDIR/absent.sock" "wheel input docker" || fail "a missing socket means Docker needs sudo"
|
||||||
|
pass "a missing socket counts as needing sudo"
|
||||||
|
|
||||||
|
# --configured follows the account's groups, not the socket.
|
||||||
|
run "$blocked_socket" "wheel input docker" --configured && fail "a configured docker group means no sudo is needed"
|
||||||
|
run "$reachable_socket" "wheel input" --configured || fail "no docker group means sudo is needed"
|
||||||
|
pass "--configured answers from the account's groups"
|
||||||
|
|
||||||
|
# The window this split exists for: sudoless Docker has just been enabled, so the
|
||||||
|
# account carries the group while the running session still cannot use it. The
|
||||||
|
# menu must offer Remove (--configured says no sudo) while lazydocker and the
|
||||||
|
# Windows VM must still prompt (default says sudo).
|
||||||
|
run "$blocked_socket" "wheel input docker" || fail "the session still needs sudo before the reboot"
|
||||||
|
run "$blocked_socket" "wheel input docker" --configured && fail "the account is already configured for sudoless Docker"
|
||||||
|
pass "the two modes disagree between enabling sudoless Docker and the reboot"
|
||||||
|
|
||||||
|
# An unknown argument is a usage error, not a silent answer either way.
|
||||||
|
run "$reachable_socket" "wheel input" --bogus 2>/dev/null && fail "an unknown flag exits non-zero"
|
||||||
|
status=0
|
||||||
|
run "$reachable_socket" "wheel input" --bogus >/dev/null 2>&1 || status=$?
|
||||||
|
(( status == 2 )) || fail "an unknown flag exits 2, not the boolean 1"
|
||||||
|
pass "an unknown flag is a usage error"
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Toggling sudoless Docker changes the docker group, which only takes effect on a
|
||||||
|
# reboot. The setup/remove commands must flag the reboot and offer to do it now
|
||||||
|
# (gum confirm), but defer it when OMARCHY_DEFER_REBOOT is set (the migration
|
||||||
|
# reuses them inside `omarchy update`, where omarchy-update-restart handles it).
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||||
|
|
||||||
|
test_dir=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$test_dir"' EXIT
|
||||||
|
home="$test_dir/home"
|
||||||
|
stub_bin="$test_dir/bin"
|
||||||
|
mkdir -p "$home" "$stub_bin"
|
||||||
|
|
||||||
|
cat >"$stub_bin/id" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
printf '%s\n' "${STUB_GROUPS:-wheel input}"
|
||||||
|
STUB
|
||||||
|
cat >"$stub_bin/sudo" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
exec "$@"
|
||||||
|
STUB
|
||||||
|
cat >"$stub_bin/usermod" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
echo "$@" >>"${USERMOD_CALLS:?}"
|
||||||
|
STUB
|
||||||
|
cat >"$stub_bin/gpasswd" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
echo "$@" >>"${GPASSWD_CALLS:?}"
|
||||||
|
STUB
|
||||||
|
cat >"$stub_bin/gum" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
touch "${GUM_CALLED:?}"
|
||||||
|
exit "${GUM_ANSWER:-0}"
|
||||||
|
STUB
|
||||||
|
cat >"$stub_bin/omarchy-system-reboot" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
touch "${REBOOT_CALLED:?}"
|
||||||
|
STUB
|
||||||
|
chmod +x "$stub_bin"/*
|
||||||
|
|
||||||
|
reboot_flag="$home/.local/state/omarchy/reboot-required"
|
||||||
|
gum_called="$test_dir/gum-called"
|
||||||
|
reboot_called="$test_dir/reboot-called"
|
||||||
|
gpasswd_calls="$test_dir/gpasswd-calls"
|
||||||
|
usermod_calls="$test_dir/usermod-calls"
|
||||||
|
|
||||||
|
run() { # command STUB_GROUPS GUM_ANSWER DEFER(0|1)
|
||||||
|
rm -f "$reboot_flag" "$gum_called" "$reboot_called" "$gpasswd_calls" "$usermod_calls"
|
||||||
|
local defer_env=()
|
||||||
|
[[ ${4:-0} == 1 ]] && defer_env=(OMARCHY_DEFER_REBOOT=1)
|
||||||
|
env HOME="$home" USER="tester" STUB_GROUPS="$2" GUM_ANSWER="$3" \
|
||||||
|
GUM_CALLED="$gum_called" REBOOT_CALLED="$reboot_called" \
|
||||||
|
GPASSWD_CALLS="$gpasswd_calls" USERMOD_CALLS="$usermod_calls" \
|
||||||
|
PATH="$stub_bin:$ROOT/bin:$PATH" "${defer_env[@]}" \
|
||||||
|
bash "$ROOT/bin/$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove, interactive, reboot confirmed -> group removed, flag set, reboot fired.
|
||||||
|
run omarchy-remove-security-sudoless-docker "wheel input docker" 0 0
|
||||||
|
grep -q -- "-d tester docker" "$gpasswd_calls" || fail "remove drops the user from the docker group"
|
||||||
|
[[ -f $reboot_flag ]] || fail "remove flags a reboot"
|
||||||
|
[[ -f $reboot_called ]] || fail "remove reboots when the prompt is confirmed"
|
||||||
|
pass "remove drops the group, flags a reboot, and reboots on confirm"
|
||||||
|
|
||||||
|
# Remove, interactive, reboot declined -> flag set, but no reboot.
|
||||||
|
run omarchy-remove-security-sudoless-docker "wheel input docker" 1 0
|
||||||
|
[[ -f $reboot_flag ]] || fail "remove still flags a reboot when the prompt is declined"
|
||||||
|
[[ ! -f $reboot_called ]] || fail "remove does not reboot when the prompt is declined"
|
||||||
|
pass "remove leaves the reboot to the user when declined"
|
||||||
|
|
||||||
|
# Remove, deferred (migration/update) -> flag set, prompt never shown.
|
||||||
|
run omarchy-remove-security-sudoless-docker "wheel input docker" 0 1
|
||||||
|
[[ -f $reboot_flag ]] || fail "deferred remove still flags a reboot"
|
||||||
|
[[ ! -f $gum_called ]] || fail "deferred remove must not prompt to reboot"
|
||||||
|
[[ ! -f $reboot_called ]] || fail "deferred remove must not reboot"
|
||||||
|
pass "deferred remove flags the reboot without prompting"
|
||||||
|
|
||||||
|
# Remove, already out of the group -> no-op, nothing flagged.
|
||||||
|
run omarchy-remove-security-sudoless-docker "wheel input" 0 0
|
||||||
|
[[ ! -f $gpasswd_calls ]] || fail "remove is a no-op when the user is not in the docker group"
|
||||||
|
[[ ! -f $reboot_flag ]] || fail "remove does not flag a reboot when nothing changed"
|
||||||
|
pass "remove is a no-op when sudoless Docker is already off"
|
||||||
|
|
||||||
|
# Setup, enable confirmed then reboot confirmed -> group added, flag set, reboot.
|
||||||
|
run omarchy-setup-security-sudoless-docker "wheel input" 0 0
|
||||||
|
grep -q -- "-aG docker tester" "$usermod_calls" || fail "setup adds the user to the docker group"
|
||||||
|
[[ -f $reboot_flag ]] || fail "setup flags a reboot"
|
||||||
|
[[ -f $reboot_called ]] || fail "setup reboots when the prompt is confirmed"
|
||||||
|
pass "setup adds the group, flags a reboot, and reboots on confirm"
|
||||||
Reference in New Issue
Block a user