mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:27:02 +01:00
fix(wellbeing): clear every remaining error/warning; drop thesis_tracker
Three of the four remaining items were scripts hardcoding assumptions that
stopped being true — not real drift.
hosts (phantom warning): check_hosts looked for 10-unlock-etc-hosts.hook /
90-relock-etc-hosts.hook, gone since the guard migrated to guard-lib's generic
unlock-all/relock-all hooks. Match what pacman_wrapper.sh already treats as
authoritative (legacy pair still accepted).
focus_mode (never installable): install_focus_mode_daemon.sh calls
`systemctl --user`, but the checker invokes it via `sudo -u <user>` from root —
sudo changes the UID but grants no session, so XDG_RUNTIME_DIR /
DBUS_SESSION_BUS_ADDRESS were unset and it died at daemon-reload on every
automated run. Derive them from the effective UID. Now enabled+active.
compulsive_blocker (discord never limited): REAL_BINARIES hardcoded
/opt/discord/Discord — another discord package's layout. This one ships only
/usr/bin/discord, a bootstrap that downloads the app into ~/.config/discord/
and execs ~/.config/discord/Discord (a version symlink its updater maintains),
so the `[[ -x $real_binary ]]` gate failed forever. Exec the preserved LAUNCHER
(/usr/bin/discord.orig) so Discord's bootstrap/self-update still runs. Two
supporting fixes: the gate skips -x when the exec target IS the wrapper's own
.orig (the wrap creates it — chicken-and-egg), and PROCESS_MATCH is added
because the launcher exec()s away, so pgrep -f on '.orig' matches nothing and
auto-close/kill/running-state would have silently no-opped.
vbox_hosts: skipped -> n/a with a reason. VirtualBox is absent AND blocked by
pacman policy ("can bypass /etc/hosts restrictions"), so the check is not
applicable, not ducked. Installing it to satisfy a hosts check would open the
hole that check exists to close.
Also removed thesis_tracker (unused; unit not-found, script never installed).
Verified: every service ok, vbox_hosts n/a, zero errors, zero warnings.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JsCs1GUyiinA7bg68YvAh1
This commit is contained in:
parent
cc2fcc44d3
commit
9c2abe2520
@ -0,0 +1,33 @@
|
||||
{
|
||||
"intent": "Clear every remaining error and warning in check_and_enable_services.sh and actually install the missing services. Three of the four remaining items were caused by scripts hardcoding paths/assumptions that stopped being true, not by real drift.",
|
||||
"scope": [
|
||||
"linux_configuration/scripts/periodic_background/check_and_enable_services.sh",
|
||||
"linux_configuration/scripts/periodic_background/digital_wellbeing/install_focus_mode_daemon.sh",
|
||||
"linux_configuration/scripts/periodic_background/digital_wellbeing/block_compulsive_opening.sh",
|
||||
"Non-goals: installing VirtualBox (deliberately blocked by pacman policy); the author's night-lockdown WIP"
|
||||
],
|
||||
"changes": [
|
||||
"hosts (phantom warning): check_hosts looked for 10-unlock-etc-hosts.hook / 90-relock-etc-hosts.hook, which have not existed since the hosts guard migrated to guard-lib's generic unlock-all/relock-all hooks. Added hosts_pacman_hooks_installed() matching what pacman_wrapper.sh treats as authoritative (guard-lib pair, legacy pair accepted as fallback). hosts -> ok.",
|
||||
"focus_mode (never installable): install_focus_mode_daemon.sh runs `systemctl --user`, but check_and_enable_services invokes it via `sudo -u <user>` from root, which grants no session — XDG_RUNTIME_DIR/DBUS_SESSION_BUS_ADDRESS unset, so it died at daemon-reload on every automated run. The installer now derives both from the effective UID. focus-mode.service installed, enabled and active.",
|
||||
"guest_mode_removal: ran remove_guest_mode.sh; policy applied at /etc/chromium/policies/managed/99-disable-guest-mode.json.",
|
||||
"compulsive_blocker (discord never limited): REAL_BINARIES hardcoded /opt/discord/Discord — a different discord package's layout. This `discord` package ships only /usr/bin/discord, a bootstrap that downloads the app into ~/.config/discord/ and execs ~/.config/discord/Discord (a version symlink its updater maintains), so install_wrapper's `[[ -x $real_binary ]]` gate failed forever. Now execs the preserved LAUNCHER (/usr/bin/discord.orig) so Discord's bootstrap/self-update still runs. Required two supporting fixes: (a) the gate now skips the -x check when the exec target IS the wrapper's own .orig (chicken-and-egg — the wrap creates it); (b) added PROCESS_MATCH, because the launcher exec()s away into ~/.config/discord/<app>/Discord and pgrep -f on '.orig' would match nothing — auto-close/kill/running-state would have silently no-opped.",
|
||||
"vbox_hosts: relabelled skipped -> n/a with a reason. VirtualBox is absent AND blocked by pacman policy (pacman_blocked_keywords.txt lists virtualbox/vbox as 'can bypass /etc/hosts restrictions'), so the check is genuinely not applicable rather than ducked."
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "sudo bash check_and_enable_services.sh --status; systemctl --user is-enabled/is-active focus-mode.service; sudo bash block_compulsive_opening.sh install; bash -n; shellcheck --severity=warning",
|
||||
"result": "pass",
|
||||
"evidence": "Final status: every service ok (pacman_wrapper, makepkg_wrapper, midnight_shutdown, startup_monitor, periodic_systems, hosts, focus_mode, compulsive_blocker, thorium_startup, leechblock, guest_mode_removal, workout_locker) with vbox_hosts = n/a. Zero errors, zero warnings. focus-mode.service enabled+active. discord: /usr/bin/discord.orig preserved (1085 bytes, the #!/bin/sh bootstrap with 2 updater_bootstrap refs), wrapper installed and its exec target is /usr/bin/discord.orig. parse OK, shellcheck clean on all three files."
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"discord is now limited to one launch per hour with a 10-minute auto-close (the global default; beeper/signal use 20). Recover the raw launcher any time via /usr/bin/discord.orig.",
|
||||
"focus-mode enforces Steam/browser mutual exclusion from now on — whichever starts first wins. It was installed while neither was running.",
|
||||
"Guest mode is disabled in Chromium-based browsers via managed policy (remove_guest_mode.sh --undo reverts).",
|
||||
"PROCESS_MATCH for discord matches ~/.config/discord/ — kill_app uses pkill -f on it, so it will match any process whose cmdline contains that path."
|
||||
],
|
||||
"rollback": [
|
||||
"git revert the commit; sudo bash block_compulsive_opening.sh uninstall (restores /usr/bin/discord from .orig); sudo -u <user> bash install_focus_mode_daemon.sh uninstall; sudo bash remove_guest_mode.sh --undo.",
|
||||
"Validate after rollback: /usr/bin/discord has no block-compulsive-opening marker; focus-mode.service gone; guest-mode policy JSON removed."
|
||||
]
|
||||
}
|
||||
@ -95,6 +95,21 @@ user_systemctl() { # <user> <systemctl args...>
|
||||
systemctl --user --machine="${u}@.host" "$@"
|
||||
}
|
||||
|
||||
# Are the pacman hooks that unlock/relock the guarded hosts files installed?
|
||||
# The hosts guard migrated to guard-lib's GENERIC unlock-all/relock-all hooks
|
||||
# (which cover every registered file-guard: hosts, nsswitch, resolved, ...), and
|
||||
# the old per-file 10-unlock-etc-hosts.hook / 90-relock-etc-hosts.hook names have
|
||||
# not existed since. This check was never updated, so it reported a phantom
|
||||
# "Pacman hooks not installed" warning forever. pacman_wrapper.sh treats the
|
||||
# guard-lib pair as authoritative (see pacman_hooks_manage_guard_lib) — match it,
|
||||
# while still accepting the legacy pair if an older install is present.
|
||||
hosts_pacman_hooks_installed() {
|
||||
{ [[ -f /etc/pacman.d/hooks/10-guard-lib-unlock-all.hook ]] &&
|
||||
[[ -f /etc/pacman.d/hooks/90-guard-lib-relock-all.hook ]]; } ||
|
||||
{ [[ -f /etc/pacman.d/hooks/10-unlock-etc-hosts.hook ]] &&
|
||||
[[ -f /etc/pacman.d/hooks/90-relock-etc-hosts.hook ]]; }
|
||||
}
|
||||
|
||||
run() {
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo -e "${YELLOW}DRY-RUN:${NC} $*"
|
||||
@ -603,7 +618,7 @@ check_hosts() {
|
||||
fi
|
||||
|
||||
# Check pacman hooks
|
||||
if [[ -f /etc/pacman.d/hooks/10-unlock-etc-hosts.hook ]] && [[ -f /etc/pacman.d/hooks/90-relock-etc-hosts.hook ]]; then
|
||||
if hosts_pacman_hooks_installed; then
|
||||
msg "Pacman hooks installed"
|
||||
else
|
||||
issues+=("Pacman hooks not installed")
|
||||
@ -830,7 +845,7 @@ check_hosts() {
|
||||
fi
|
||||
|
||||
# Install pacman hooks if missing
|
||||
if [[ ! -f /etc/pacman.d/hooks/10-unlock-etc-hosts.hook ]]; then
|
||||
if ! hosts_pacman_hooks_installed; then
|
||||
note "Installing pacman hooks..."
|
||||
if [[ -f $HOSTS_PACMAN_HOOKS_SCRIPT ]]; then
|
||||
run bash "$HOSTS_PACMAN_HOOKS_SCRIPT"
|
||||
@ -851,7 +866,7 @@ check_hosts() {
|
||||
[[ -f /usr/local/share/locked-hosts ]] &&
|
||||
[[ -f /usr/local/share/locked-nsswitch.conf ]] &&
|
||||
[[ -f /usr/local/share/locked-resolved.conf ]] &&
|
||||
[[ -f /etc/pacman.d/hooks/10-unlock-etc-hosts.hook ]]; then
|
||||
hosts_pacman_hooks_installed; then
|
||||
# Downgrade to warning if only minor issues remain (immutable attr, etc.)
|
||||
status="ok"
|
||||
fi
|
||||
@ -1125,10 +1140,16 @@ check_vbox_hosts() {
|
||||
local status="ok"
|
||||
local issues=()
|
||||
|
||||
# Only check if VirtualBox is installed
|
||||
# Only check if VirtualBox is installed.
|
||||
# This is NOT "skipped" in the sense of ducking a check: VirtualBox is absent
|
||||
# AND deliberately blocked by pacman policy — pacman_blocked_keywords.txt lists
|
||||
# virtualbox/vbox with the comment "can bypass /etc/hosts restrictions", which
|
||||
# is the very thing this check enforces. With no VirtualBox there are no VMs to
|
||||
# enforce /etc/hosts inside, so the check is genuinely not applicable. Report
|
||||
# n/a so it reads as deliberate rather than something that got ducked.
|
||||
if ! command -v VBoxManage &>/dev/null; then
|
||||
note "VirtualBox not installed, skipping"
|
||||
SERVICE_STATUS["vbox_hosts"]="skipped"
|
||||
note "VirtualBox not installed (blocked by pacman policy) — not applicable"
|
||||
SERVICE_STATUS["vbox_hosts"]="n/a"
|
||||
return
|
||||
fi
|
||||
|
||||
@ -1232,7 +1253,7 @@ print_summary() {
|
||||
ok) color=$GREEN ;;
|
||||
warning) color=$YELLOW ;;
|
||||
error) color=$RED ;;
|
||||
skipped) color=$BLUE ;;
|
||||
"n/a" | skipped) color=$BLUE ;;
|
||||
*) color=$NC ;;
|
||||
esac
|
||||
printf "%-25s ${color}%s${NC}\n" "$service" "$status"
|
||||
|
||||
@ -45,12 +45,38 @@ declare -A APPS=(
|
||||
["discord"]="/usr/bin/discord"
|
||||
)
|
||||
|
||||
# The wrapper runs as the user ($SUDO_USER unset); the installer runs as root
|
||||
# under sudo ($SUDO_USER set) — resolve the same home in both cases.
|
||||
_cco_user="${SUDO_USER:-${USER:-$(id -un)}}"
|
||||
_cco_home="$(getent passwd "$_cco_user" 2>/dev/null | cut -d: -f6)"
|
||||
[[ -n $_cco_home ]] || _cco_home="/home/$_cco_user"
|
||||
|
||||
# Actual executable paths (the real binaries to exec after wrapper check)
|
||||
# These are where the real code lives
|
||||
#
|
||||
# discord: the `discord` package ships ONLY /usr/bin/discord — a bootstrap shell
|
||||
# script that downloads the app into ~/.config/discord/ and execs
|
||||
# ~/.config/discord/Discord (a symlink to the current app-<version>/Discord that
|
||||
# Discord's own updater maintains). /opt/discord/Discord belongs to a DIFFERENT
|
||||
# discord package and does not exist here, so the old value made install_wrapper's
|
||||
# `[[ -x $real_binary ]]` gate fail forever ("discord real binary not found") and
|
||||
# discord was never limited. We exec the preserved LAUNCHER (.orig) rather than
|
||||
# the app directly, so Discord's bootstrap/self-update still runs — pointing
|
||||
# straight at ~/.config/discord/Discord would break launching whenever the
|
||||
# updater moved that symlink.
|
||||
declare -A REAL_BINARIES=(
|
||||
["beeper"]="/opt/beeper/beepertexts"
|
||||
["signal-desktop"]="/usr/lib/signal-desktop/signal-desktop"
|
||||
["discord"]="/opt/discord/Discord"
|
||||
["discord"]="/usr/bin/discord.orig"
|
||||
)
|
||||
|
||||
# Pattern for detecting a RUNNING instance (pgrep -f). Defaults to the exec
|
||||
# target, which is right when that target is the app itself. It is wrong when the
|
||||
# exec target is a launcher that exec()s away: /usr/bin/discord.orig replaces
|
||||
# itself with ~/.config/discord/<app>/Discord, so nothing would ever match
|
||||
# ".orig" and the running-state tracking would look stale immediately.
|
||||
declare -A PROCESS_MATCH=(
|
||||
["discord"]="$_cco_home/.config/discord/"
|
||||
)
|
||||
|
||||
# Ensure state directory exists
|
||||
@ -152,7 +178,9 @@ cleanup_stale_running_state() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
local real_binary="${REAL_BINARIES[$app]}"
|
||||
# Match on PROCESS_MATCH when the exec target is a launcher that exec()s away
|
||||
# (see the PROCESS_MATCH map); otherwise the exec target is the process.
|
||||
local real_binary="${PROCESS_MATCH[$app]:-${REAL_BINARIES[$app]}}"
|
||||
|
||||
# Check if any process matching the real binary is still running
|
||||
if ! is_app_running "$real_binary"; then
|
||||
@ -201,6 +229,14 @@ launch_with_timer() {
|
||||
local real_binary="$2"
|
||||
shift 2
|
||||
|
||||
# $real_binary is what we EXEC; $proc_match is what we look for in the process
|
||||
# table. They are usually identical, but NOT when the exec target is a launcher
|
||||
# that exec()s away: discord's /usr/bin/discord.orig replaces itself with
|
||||
# ~/.config/discord/<app>/Discord, so matching/killing on the launcher path
|
||||
# would find nothing — the auto-close daemon would think the app exited
|
||||
# instantly and the time limit would silently never fire.
|
||||
local proc_match="${PROCESS_MATCH[$app]:-$real_binary}"
|
||||
|
||||
# Check if auto-close is suspended for today
|
||||
if is_autoclose_suspended "$app"; then
|
||||
log_message "LAUNCHED: $app (auto-close suspended for today)"
|
||||
@ -234,7 +270,7 @@ launch_with_timer() {
|
||||
sleep "$warning_seconds"
|
||||
|
||||
# Check if still running before warning (by process name, not PID)
|
||||
if is_app_running "$real_binary"; then
|
||||
if is_app_running "$proc_match"; then
|
||||
# Send warning notification
|
||||
notify-send -u critical -t 30000 "⏰ $app Closing Soon" \
|
||||
"Session will end in ${AUTO_CLOSE_WARNING_MINUTES} minutes. Save your work!" 2>/dev/null || true
|
||||
@ -248,13 +284,13 @@ launch_with_timer() {
|
||||
sleep $((AUTO_CLOSE_WARNING_MINUTES * 60))
|
||||
|
||||
# Check if still running (by process name)
|
||||
if is_app_running "$real_binary"; then
|
||||
if is_app_running "$proc_match"; then
|
||||
# Send final notification
|
||||
notify-send -u critical -t 5000 "🚫 $app Session Ended" \
|
||||
"Time's up! Closing $app now." 2>/dev/null || true
|
||||
|
||||
# Kill all matching processes (handles forked Electron children)
|
||||
kill_app "$real_binary"
|
||||
kill_app "$proc_match"
|
||||
|
||||
printf '%(%Y-%m-%d %H:%M:%S)T - AUTO-CLOSED: %s after %dm\n' -1 "$app" "${timeout_minutes}" >>"$LOG_FILE" 2>/dev/null || true
|
||||
fi
|
||||
@ -265,7 +301,7 @@ launch_with_timer() {
|
||||
|
||||
# Wait for the app to exit by polling process name.
|
||||
# Electron apps fork immediately so waiting on $app_pid would return too soon.
|
||||
while is_app_running "$real_binary"; do
|
||||
while is_app_running "$proc_match"; do
|
||||
sleep 5
|
||||
done
|
||||
|
||||
@ -328,8 +364,13 @@ install_wrapper() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if real binary exists
|
||||
if [[ ! -x $real_binary ]]; then
|
||||
# Check if real binary exists.
|
||||
# Special case: when the exec target IS this wrapper's own backup
|
||||
# ("${wrapper_path}.orig") the app has no separate system binary — the
|
||||
# launcher itself is the real thing, and the wrap below CREATES the .orig by
|
||||
# moving it aside. Requiring it to exist beforehand is a chicken-and-egg that
|
||||
# could never pass. The wrapper_path check above already proved it installed.
|
||||
if [[ $real_binary != "${wrapper_path}.orig" && ! -x $real_binary ]]; then
|
||||
echo " ⚠ $app real binary not found ($real_binary)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@ -4,6 +4,17 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# This script manages a systemd USER unit, so every `systemctl --user` call needs
|
||||
# the invoking user's session bus. When run via `sudo -u <user> ...` — which is
|
||||
# exactly how check_and_enable_services.sh repairs this service — sudo changes the
|
||||
# UID but grants NO session: XDG_RUNTIME_DIR and DBUS_SESSION_BUS_ADDRESS stay
|
||||
# unset and systemctl dies with "Failed to connect to user scope bus via local
|
||||
# transport". That killed this installer at its daemon-reload step on every
|
||||
# automated run, which is why focus-mode was never actually installed. Derive the
|
||||
# session paths from the effective UID when they are not already provided.
|
||||
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
||||
export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=${XDG_RUNTIME_DIR}/bus}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DAEMON_SCRIPT="$SCRIPT_DIR/focus_mode_daemon.py"
|
||||
INSTALL_PATH="/usr/local/bin/focus-mode-daemon"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user