Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ help:
@printf ' %-18s %s\n' "PACKAGE_WITH_UPDATER=0" "Build packages without codex-update-manager or the updater service"
@printf ' %-18s %s\n' "CODEX_CLI_BUNDLE_SOURCE=..." "Embed an installed Codex CLI package in a local AppImage"
@printf ' %-18s %s\n' "MAX_BUILD_THREADS=8" "Set supported build jobs/compression threads (default: 0, tool/user defaults)"
@printf ' %-18s %s\n' "CODEX_SUDO_ALERT=1" "Play a best-effort alert before an interactive sudo password prompt"
@printf ' %-18s %s\n' "RPM_BINARY_PAYLOAD=..." "Advanced RPM payload flags override (default follows MAX_BUILD_THREADS)"
@printf ' %-18s %s\n' "APPIMAGETOOL=..." "Override the appimagetool executable for make appimage"
@printf ' %-18s %s\n' "DEB=/path/file.deb" "Override the .deb used by make install"
Expand All @@ -127,6 +128,7 @@ help:
@printf ' %s\n' "make setup-native"
@printf ' %s\n' "make bootstrap-native"
@printf ' %s\n' "make install-native"
@printf ' %s\n' "CODEX_SUDO_ALERT=1 make install-native"
@printf ' %s\n' "PACKAGE_WITH_UPDATER=0 make update-native"
@printf ' %s\n' "CODEX_CLI_BUNDLE_SOURCE=/path/to/node_modules/@openai/codex make appimage"
@printf ' %s\n' "make inspect-upstream DMG=/tmp/Codex.dmg"
Expand Down Expand Up @@ -317,35 +319,35 @@ install:
echo "[make] No pacman package found. Run 'make pacman' first." >&2; exit 1; \
fi; \
echo "[make] Installing $$pkg"; \
sudo pacman -U --noconfirm "$$pkg"; \
"$(CURDIR)/scripts/sudo-with-alert.sh" pacman -U --noconfirm "$$pkg"; \
elif [ "$$format" = "rpm" ] && command -v dnf >/dev/null 2>&1; then \
rpm="$${RPM:-$$(latest_matching_file "$(RPM_GLOB)")}"; \
if [ -z "$$rpm" ]; then \
echo "[make] No RPM package found. Run 'make rpm' first." >&2; exit 1; \
fi; \
echo "[make] Installing $$rpm"; \
sudo dnf install -y "$$rpm"; \
"$(CURDIR)/scripts/sudo-with-alert.sh" dnf install -y "$$rpm"; \
elif [ "$$format" = "rpm" ] && command -v zypper >/dev/null 2>&1; then \
rpm="$${RPM:-$$(latest_matching_file "$(RPM_GLOB)")}"; \
if [ -z "$$rpm" ]; then \
echo "[make] No RPM package found. Run 'make rpm' first." >&2; exit 1; \
fi; \
echo "[make] Installing $$rpm"; \
sudo zypper --non-interactive --no-gpg-checks install -y "$$rpm"; \
"$(CURDIR)/scripts/sudo-with-alert.sh" zypper --non-interactive --no-gpg-checks install -y "$$rpm"; \
elif [ "$$format" = "rpm" ]; then \
rpm="$${RPM:-$$(latest_matching_file "$(RPM_GLOB)")}"; \
if [ -z "$$rpm" ]; then \
echo "[make] No RPM package found. Run 'make rpm' first." >&2; exit 1; \
fi; \
echo "[make] Installing $$rpm"; \
sudo rpm -Uvh "$$rpm"; \
"$(CURDIR)/scripts/sudo-with-alert.sh" rpm -Uvh "$$rpm"; \
elif [ "$$format" = "deb" ]; then \
deb="$${DEB:-$$(latest_matching_file "$(DEB_GLOB)")}"; \
if [ -z "$$deb" ]; then \
echo "[make] No Debian package found. Run 'make deb' first." >&2; exit 1; \
fi; \
echo "[make] Installing $$deb"; \
sudo dpkg -i "$$deb"; \
"$(CURDIR)/scripts/sudo-with-alert.sh" dpkg -i "$$deb"; \
else \
echo "[make] No supported package manager found (dpkg, rpm, zypper, or pacman)." >&2; exit 1; \
fi
Expand Down
13 changes: 13 additions & 0 deletions docs/native-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ If dependencies are already installed:
make install-native
```

To play a best-effort sound immediately before an interactive `sudo` password
prompt, opt in with `CODEX_SUDO_ALERT=1`:

```bash
CODEX_SUDO_ALERT=1 make install-native
CODEX_SUDO_ALERT=1 make bootstrap-native
CODEX_SUDO_ALERT=1 make update-native
```

The alert is skipped while the existing `sudo` credential timestamp is valid.
It tries the desktop sound system first and falls back to the terminal bell.
Missing audio tools, sound files, or audio services never block installation.

## Guided Setup

```bash
Expand Down
4 changes: 4 additions & 0 deletions scripts/install-deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/lib/linux-target-detect.sh"

sudo() {
"$SCRIPT_DIR/sudo-with-alert.sh" "$@"
}

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
Expand Down
56 changes: 56 additions & 0 deletions scripts/sudo-with-alert.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
set -eu

play_sudo_alert_command() {
if command -v timeout >/dev/null 2>&1; then
timeout 1s "$@"
else
"$@"
fi
}

play_sudo_alert() {
local sound_file

sound_file="/usr/share/sounds/freedesktop/stereo/dialog-warning.oga"
if command -v pw-play >/dev/null 2>&1 \
&& [ -r "$sound_file" ] \
&& play_sudo_alert_command pw-play "$sound_file" >/dev/null 2>&1; then
return 0
fi

if command -v paplay >/dev/null 2>&1 \
&& [ -r "$sound_file" ] \
&& play_sudo_alert_command paplay "$sound_file" >/dev/null 2>&1; then
return 0
fi

if command -v canberra-gtk-play >/dev/null 2>&1 \
&& play_sudo_alert_command canberra-gtk-play -i dialog-warning >/dev/null 2>&1; then
return 0
fi

for sound_file in \
/usr/share/sounds/alsa/Front_Center.wav \
/usr/share/sounds/sound-icons/prompt.wav; do
if command -v aplay >/dev/null 2>&1 \
&& [ -r "$sound_file" ] \
&& play_sudo_alert_command aplay -q "$sound_file" >/dev/null 2>&1; then
return 0
fi
done

printf '\a' >&2 || true
}

if [ "${CODEX_SUDO_ALERT:-0}" != "1" ]; then
exec sudo "$@"
fi

if sudo -n -v 2>/dev/null; then
exec sudo "$@"
fi

play_sudo_alert || true
sudo -v
exec sudo "$@"
100 changes: 100 additions & 0 deletions tests/scripts_smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2777,6 +2777,104 @@ test_native_shortcut_targets_compose_existing_flows() {
assert_contains "$setup_log" 'bash scripts/bootstrap-wizard.sh'
}

test_sudo_alert_wrapper() {
info "Checking opt-in sudo password alerts"
local workspace="$TMP_DIR/sudo-alert"
local bin_dir="$workspace/bin"
local log_file="$workspace/events.log"
local wrapper="$REPO_DIR/scripts/sudo-with-alert.sh"
mkdir -p "$bin_dir"

cat > "$bin_dir/sudo" <<'EOF'
#!/usr/bin/env bash
set -eu
printf 'sudo:%s\n' "$*" >> "$SUDO_ALERT_TEST_LOG"
if [ "${1-}" = "-n" ] && [ "${2-}" = "-v" ]; then
exit "${SUDO_ALERT_TEST_CACHE_STATUS:-0}"
fi
if [ "${1-}" = "-v" ]; then
exit "${SUDO_ALERT_TEST_AUTH_STATUS:-0}"
fi
exit "${SUDO_ALERT_TEST_COMMAND_STATUS:-0}"
EOF
chmod +x "$bin_dir/sudo"

cat > "$bin_dir/pw-play" <<'EOF'
#!/usr/bin/env bash
set -eu
printf 'alert:%s\n' "$*" >> "$SUDO_ALERT_TEST_LOG"
exit "${SUDO_ALERT_TEST_SOUND_STATUS:-0}"
EOF
chmod +x "$bin_dir/pw-play"

: > "$log_file"
PATH="$bin_dir:$HOST_TOOL_PATH" SUDO_ALERT_TEST_LOG="$log_file" \
"$wrapper" true
assert_occurrence_count "$log_file" '^sudo:true$' 1
assert_not_contains "$log_file" 'sudo:-n -v'
assert_not_contains "$log_file" 'alert:'

: > "$log_file"
CODEX_SUDO_ALERT=1 PATH="$bin_dir:$HOST_TOOL_PATH" SUDO_ALERT_TEST_LOG="$log_file" \
"$wrapper" true
assert_contains "$log_file" 'sudo:-n -v'
assert_not_contains "$log_file" 'alert:'
assert_contains "$log_file" 'sudo:true'

: > "$log_file"
CODEX_SUDO_ALERT=1 SUDO_ALERT_TEST_CACHE_STATUS=1 \
PATH="$bin_dir:$HOST_TOOL_PATH" SUDO_ALERT_TEST_LOG="$log_file" \
"$wrapper" true
[ "$(sed -n '1p' "$log_file")" = 'sudo:-n -v' ] || fail "Expected cached sudo check first"
[ "$(sed -n '2p' "$log_file")" = 'alert:/usr/share/sounds/freedesktop/stereo/dialog-warning.oga' ] \
|| fail "Expected alert before authentication"
[ "$(sed -n '3p' "$log_file")" = 'sudo:-v' ] || fail "Expected sudo authentication after alert"
[ "$(sed -n '4p' "$log_file")" = 'sudo:true' ] || fail "Expected command after authentication"

: > "$log_file"
CODEX_SUDO_ALERT=1 SUDO_ALERT_TEST_CACHE_STATUS=1 SUDO_ALERT_TEST_SOUND_STATUS=1 \
PATH="$bin_dir:$HOST_TOOL_PATH" SUDO_ALERT_TEST_LOG="$log_file" \
"$wrapper" true 2>/dev/null
assert_contains "$log_file" 'sudo:-v'
assert_contains "$log_file" 'sudo:true'

: > "$log_file"
local status=0
CODEX_SUDO_ALERT=1 SUDO_ALERT_TEST_CACHE_STATUS=1 SUDO_ALERT_TEST_AUTH_STATUS=23 \
PATH="$bin_dir:$HOST_TOOL_PATH" SUDO_ALERT_TEST_LOG="$log_file" \
"$wrapper" true 2>/dev/null || status=$?
[ "$status" -eq 23 ] || fail "Expected sudo authentication failure status, got $status"
assert_not_contains "$log_file" 'sudo:true'

: > "$log_file"
status=0
CODEX_SUDO_ALERT=1 SUDO_ALERT_TEST_COMMAND_STATUS=17 \
PATH="$bin_dir:$HOST_TOOL_PATH" SUDO_ALERT_TEST_LOG="$log_file" \
"$wrapper" true || status=$?
[ "$status" -eq 17 ] || fail "Expected privileged command status, got $status"
}

test_native_sudo_alert_wiring() {
info "Checking native targets route sudo through the alert wrapper"
local install_log="$TMP_DIR/make-install-sudo-alert.log"
local bootstrap_log="$TMP_DIR/make-bootstrap-sudo-alert.log"
local update_log="$TMP_DIR/make-update-sudo-alert.log"

CODEX_SUDO_ALERT=1 make -n -C "$REPO_DIR" install >"$install_log"
assert_occurrence_count "$install_log" 'scripts/sudo-with-alert.sh' 5

CODEX_SUDO_ALERT=1 make -n -C "$REPO_DIR" bootstrap-native >"$bootstrap_log"
assert_contains "$bootstrap_log" 'bash scripts/install-deps.sh'
assert_contains "$bootstrap_log" 'install-native'

CODEX_SUDO_ALERT=1 make -n -C "$REPO_DIR" update-native >"$update_log"
assert_contains "$update_log" 'git pull --ff-only'
assert_contains "$update_log" 'install-native'

assert_contains "$REPO_DIR/scripts/install-deps.sh" 'sudo-with-alert.sh'
assert_contains "$REPO_DIR/Makefile" 'CODEX_SUDO_ALERT=1'
}

test_fedora_dependency_bootstrap_installs_rpmbuild() {
info "Checking Fedora dependency bootstrap includes rpmbuild and C++ build tools"
local install_deps="$REPO_DIR/scripts/install-deps.sh"
Expand Down Expand Up @@ -9082,6 +9180,8 @@ main() {
test_transactional_install_uses_managed_node_and_isolated_reports
test_installer_cleanup_handles_readonly_trees
test_native_shortcut_targets_compose_existing_flows
test_sudo_alert_wrapper
test_native_sudo_alert_wiring
test_fedora_dependency_bootstrap_installs_rpmbuild
test_fedora_atomic_rpm_ostree_target_detection
test_setup_native_wizard_noninteractive_feature_writer
Expand Down
Loading