295 lines
15 KiB
Bash
Executable File
295 lines
15 KiB
Bash
Executable File
#!/bin/bash
|
|
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
|
# ║ setup/audit-packages.sh — Package source audit tool ║
|
|
# ║ ║
|
|
# ║ PURPOSE: ║
|
|
# ║ Verifies that installed packages come from the expected source ║
|
|
# ║ (official pacman repos, AUR, or Flatpak). Reports: ║
|
|
# ║ - Missing packages that should be installed ║
|
|
# ║ - Packages installed from the wrong source (e.g. pacman pkg from AUR) ║
|
|
# ║ - Unexpected foreign/AUR packages not declared in setup scripts ║
|
|
# ║ ║
|
|
# ║ USAGE: ║
|
|
# ║ bash audit-packages.sh # report only ║
|
|
# ║ bash audit-packages.sh --fix # report + auto-reinstall wrong-source ║
|
|
# ║ bash audit-packages.sh -f # shorthand for --fix ║
|
|
# ║ ║
|
|
# ║ WHY THIS TOOL EXISTS: ║
|
|
# ║ On Arch, some packages exist in both the official repos AND the AUR ║
|
|
# ║ (often with a different build/version). If an AUR package shadows an ║
|
|
# ║ official one, pacman -Syu won't update it. This script detects drift. ║
|
|
# ║ ║
|
|
# ║ EXIT CODES: ║
|
|
# ║ 0 — all checks passed ║
|
|
# ║ 1 — one or more issues found ║
|
|
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
|
|
|
# Verifies installed packages come from the expected source (pacman/AUR/flatpak).
|
|
# Reports missing packages, wrong-source installs, and unexpected foreign packages.
|
|
# Pass --fix / -f to automatically reinstall packages from the correct source.
|
|
set -euo pipefail
|
|
|
|
# ── Output formatting ──────────────────────────────────────────────────────────
|
|
# ANSI color codes for colored terminal output
|
|
|
|
RED="\e[31m"; YELLOW="\e[33m"; GREEN="\e[32m"; CYAN="\e[36m"; BOLD="\e[1m"; RESET="\e[0m"
|
|
|
|
ok() { echo -e " ${GREEN}✔${RESET} $1"; } # Green checkmark: package is correct
|
|
warn() { echo -e " ${YELLOW}⚠${RESET} $1"; } # Yellow warning: non-critical issue
|
|
err() { echo -e " ${RED}✘${RESET} $1"; } # Red X: package missing or wrong
|
|
hdr() { echo -e "\n${BOLD}${CYAN}$1${RESET}"; } # Bold cyan section header
|
|
fix() { echo -e " ${CYAN}↺${RESET} $1"; } # Cyan spinner: fix action in progress
|
|
|
|
# ── Fix mode flag ─────────────────────────────────────────────────────────────
|
|
# Parse the --fix / -f argument. When FIX=1, wrong-source packages will be
|
|
# automatically reinstalled from the correct source at the end of the audit.
|
|
|
|
FIX=0
|
|
[[ "${1:-}" == "--fix" || "${1:-}" == "-f" ]] && FIX=1
|
|
|
|
# ── Issue counter ─────────────────────────────────────────────────────────────
|
|
# ISSUES tracks the number of problems found. The final exit code is 1 if > 0.
|
|
ISSUES=0
|
|
flag() { ISSUES=$((ISSUES + 1)); } # Increment the issue counter
|
|
|
|
# ── Wrong-source package lists ────────────────────────────────────────────────
|
|
# These arrays collect packages that need reinstallation when --fix is used.
|
|
WRONG_SOURCE_OFFICIAL=() # expected from pacman, installed from AUR
|
|
WRONG_SOURCE_AUR=() # expected from AUR, installed from official
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Expected package sources — keep in sync with setup/modules/
|
|
# ---------------------------------------------------------------------------
|
|
# IMPORTANT: When you add packages to any module script, add them here too.
|
|
# The lists are manually maintained to stay in sync with what modules install.
|
|
|
|
# ── PACMAN_PKGS: packages that MUST come from official Arch repositories ──────
|
|
# If any of these are found to be installed from the AUR instead, that's a drift
|
|
# issue — the AUR version may not receive official security updates.
|
|
PACMAN_PKGS=(
|
|
# core-packages.sh
|
|
7zip arch-install-scripts atftp atool
|
|
base base-devel bind bluez btrfs-progs btop
|
|
cockpit cockpit-files cockpit-podman cronie curl
|
|
distrobox fail2ban fastfetch fd ffmpeg firefox flatpak
|
|
gcc glib2 greetd-tuigreet grub
|
|
htop inetutils iwd jq ldns less libpulse linux linux-firmware
|
|
man-db mc nano neovim networkmanager
|
|
openssh pciutils pipewire podman podman-compose
|
|
python python-pip qrencode ruby-pkg-config rust rustup
|
|
ipcalc iputils mtr net-tools nmap
|
|
smartmontools symlinks tcpdump traceroute tree
|
|
udisks2 udisks2-btrfs udiskie ufw usbutils
|
|
vim vnstat wget wireplumber wireless_tools wpa_supplicant wprs
|
|
yazi zip unzip zram-generator
|
|
# shell-setup.sh
|
|
zsh pyright bash atftp bash-language-server clang fzf hyfetch
|
|
lua-language-server micro pulsemixer z dysk glow
|
|
# hyprland.sh (official-repo portion)
|
|
hyprland hyprcursor wl-clipboard hyprpaper hyprlock wofi kitty dunst
|
|
nwg-dock-hyprland nwg-drawer nwg-menu nwg-look
|
|
cmake meson cpio pkgconf
|
|
hyprsunset hypridle ksshaskpass
|
|
nm-connection-editor network-manager-applet blueman
|
|
pipewire alsa-utils greetd-tuigreet
|
|
grim slurp gst-plugin-pipewire imagemagick
|
|
nerd-fonts otf-font-awesome
|
|
pipewire-alsa pipewire-jack pipewire-pulse
|
|
qt5-wayland qt6-wayland swww ttf-jetbrains-mono
|
|
qt6ct xdg-desktop-portal-hyprland xdg-utils
|
|
xorg-server xorg-xinit papirus-icon-theme
|
|
cool-retro-term qalculate-gtk dbus
|
|
thunar tumbler thunar-archive-plugin thunar-shares-plugin thunar-volman
|
|
hyprpicker pcmanfm-qt ly
|
|
hyprpolkitagent pavucontrol playerctl wf-recorder sound-theme-freedesktop
|
|
kew
|
|
)
|
|
|
|
# ── AUR_PKGS: packages that MUST come from the AUR ───────────────────────────
|
|
# If any of these are found in the official repos instead, it may mean Arch has
|
|
# promoted them — but could also mean a naming collision. Flagged for review.
|
|
# NOTE: AUR packages are treated as optional (warn, not err) when missing,
|
|
# because they may be legitimately excluded on some systems.
|
|
AUR_PKGS=(
|
|
# hyprland.sh AUR portion (not in official repos)
|
|
hyprland-workspaces vicinae-bin bluetuith wvkbd iwmenu
|
|
walker-bin ulauncher bzmenu wofi-calc bri chamel
|
|
# optional apps (only installed if selected in TUI)
|
|
pamtester # PAM authentication tester
|
|
pinta # Simple image editor (paint.net-like)
|
|
localsend # LAN file transfer
|
|
vesktop # Discord with Vencord themes
|
|
onlyoffice-bin # Office suite (pre-built binary from AUR)
|
|
vintagestory # Survival game
|
|
wprs-git # Wayland proxy (git version)
|
|
zfs-dkms # ZFS kernel module
|
|
)
|
|
|
|
# ── FLATPAK_PKGS: apps installed via Flatpak (Flathub) ───────────────────────
|
|
# These are cross-distro app bundles. Listed by their Flatpak app ID.
|
|
FLATPAK_PKGS=(
|
|
org.prismlauncher.PrismLauncher # Minecraft launcher
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Snapshot current state
|
|
# ---------------------------------------------------------------------------
|
|
# Take a snapshot of what's installed now so we don't repeatedly call pacman.
|
|
# This also ensures consistent results across the whole run.
|
|
|
|
ALL_INSTALLED=$(pacman -Qq 2>/dev/null) # All installed packages (name only)
|
|
FOREIGN=$(pacman -Qmq 2>/dev/null) # AUR / manually installed (foreign) packages
|
|
OFFICIAL=$(pacman -Qnq 2>/dev/null) # Packages from official sync repos
|
|
|
|
# Helper functions for membership testing — grep -qx matches whole lines exactly
|
|
is_installed() { echo "$ALL_INSTALLED" | grep -qx "$1"; }
|
|
is_from_official() { echo "$OFFICIAL" | grep -qx "$1"; }
|
|
is_from_aur() { echo "$FOREIGN" | grep -qx "$1"; }
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. Check pacman packages
|
|
# ---------------------------------------------------------------------------
|
|
# For each expected official package:
|
|
# - NOT installed: hard error (✘) — increment issue counter
|
|
# - Installed from AUR: warning (⚠) — drift; increment counter, queue for fix
|
|
# - Installed from official: pass (✔)
|
|
|
|
hdr "1/3 Official-repo packages (pacman)"
|
|
|
|
for pkg in "${PACMAN_PKGS[@]}"; do
|
|
if ! is_installed "$pkg"; then
|
|
err "$pkg — NOT INSTALLED"; flag
|
|
elif is_from_aur "$pkg"; then
|
|
# This package should come from official repos but is installed from AUR.
|
|
# This means `pacman -Syu` won't update it — potential security gap.
|
|
warn "$pkg — installed, but from AUR instead of official repo"; flag
|
|
WRONG_SOURCE_OFFICIAL+=("$pkg")
|
|
else
|
|
ok "$pkg"
|
|
fi
|
|
done
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. Check AUR packages
|
|
# ---------------------------------------------------------------------------
|
|
# For each expected AUR package:
|
|
# - NOT installed: soft warning — AUR packages are typically optional
|
|
# - Installed from official repo: warning — may get wrong version from Arch
|
|
# - Installed from AUR: pass (✔)
|
|
|
|
hdr "2/3 AUR packages (yay)"
|
|
|
|
for pkg in "${AUR_PKGS[@]}"; do
|
|
if ! is_installed "$pkg"; then
|
|
# AUR packages are often optional (selected in TUI installer), so this
|
|
# is a warning rather than an error — intentional omission is common.
|
|
warn "$pkg — not installed (optional — may be intentional)"
|
|
elif is_from_official "$pkg"; then
|
|
# This package should come from AUR but is installed from official repos.
|
|
# The official version may differ (newer or older) — flagged for review.
|
|
warn "$pkg — installed from official repo, not AUR (may need AUR build for correct version)"; flag
|
|
WRONG_SOURCE_AUR+=("$pkg")
|
|
else
|
|
ok "$pkg"
|
|
fi
|
|
done
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. Check flatpak packages
|
|
# ---------------------------------------------------------------------------
|
|
# Flatpak packages are checked separately using the `flatpak` command.
|
|
# Missing Flatpaks are soft warnings since they're always optional.
|
|
|
|
hdr "3/3 Flatpak packages"
|
|
|
|
if command -v flatpak &>/dev/null; then
|
|
# List installed Flatpak apps (not runtimes) in the 'application' column only
|
|
FLATPAK_INSTALLED=$(flatpak list --app --columns=application 2>/dev/null)
|
|
for pkg in "${FLATPAK_PKGS[@]}"; do
|
|
if echo "$FLATPAK_INSTALLED" | grep -qx "$pkg"; then
|
|
ok "$pkg"
|
|
else
|
|
warn "$pkg — not installed (optional — may be intentional)"
|
|
fi
|
|
done
|
|
else
|
|
warn "flatpak not found — skipping flatpak checks"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. Flag unexpected foreign (AUR) packages not in our lists
|
|
# ---------------------------------------------------------------------------
|
|
# Any AUR package installed on the system but NOT in our AUR_PKGS list is
|
|
# unexpected. These may have been installed manually or by other tools.
|
|
# They're highlighted for human review — not counted as issues.
|
|
|
|
hdr "Bonus: foreign packages not declared in setup scripts"
|
|
|
|
# Build a newline-separated set of declared AUR packages for grep matching
|
|
AUR_SET=$(printf "%s\n" "${AUR_PKGS[@]}")
|
|
while IFS= read -r pkg; do
|
|
# If the foreign package is not in our declared AUR list, highlight it
|
|
if ! echo "$AUR_SET" | grep -qx "$pkg"; then
|
|
echo -e " ${CYAN}?${RESET} $pkg — foreign package not in setup scripts"
|
|
fi
|
|
done <<< "$FOREIGN"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Fix: reinstall wrong-source packages
|
|
# ---------------------------------------------------------------------------
|
|
# When --fix is passed, reinstall any packages found in the wrong source.
|
|
# Official packages are reinstalled with pacman; AUR packages with yay --aur.
|
|
|
|
FIXED=0
|
|
|
|
if [ "$FIX" -eq 1 ]; then
|
|
if [ ${#WRONG_SOURCE_OFFICIAL[@]} -gt 0 ] || [ ${#WRONG_SOURCE_AUR[@]} -gt 0 ]; then
|
|
hdr "Reinstalling wrong-source packages"
|
|
fi
|
|
|
|
# Reinstall from official repo (packages that were incorrectly from AUR)
|
|
for pkg in "${WRONG_SOURCE_OFFICIAL[@]}"; do
|
|
fix "Reinstalling $pkg from official repo (was AUR)..."
|
|
# pacman -S without --aur ensures it comes from the sync database
|
|
if sudo pacman -S --noconfirm "$pkg"; then
|
|
ok "$pkg reinstalled from official repo"
|
|
FIXED=$((FIXED + 1))
|
|
ISSUES=$((ISSUES - 1)) # Remove from issue count since it's now fixed
|
|
else
|
|
err "$pkg reinstall failed"
|
|
fi
|
|
done
|
|
|
|
# Reinstall from AUR (packages that were incorrectly from official repos)
|
|
for pkg in "${WRONG_SOURCE_AUR[@]}"; do
|
|
fix "Reinstalling $pkg from AUR (was official repo)..."
|
|
# --aur flag ensures yay only looks in the AUR, not official repos
|
|
if yay -S --aur --noconfirm "$pkg"; then
|
|
ok "$pkg reinstalled from AUR"
|
|
FIXED=$((FIXED + 1))
|
|
ISSUES=$((ISSUES - 1))
|
|
else
|
|
err "$pkg reinstall failed"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Summary
|
|
# ---------------------------------------------------------------------------
|
|
|
|
echo
|
|
if [ "$FIX" -eq 1 ] && [ "$FIXED" -gt 0 ]; then
|
|
echo -e "${GREEN}${BOLD}Fixed ${FIXED} wrong-source package(s).${RESET}"
|
|
fi
|
|
|
|
if [ "$ISSUES" -eq 0 ]; then
|
|
echo -e "${GREEN}${BOLD}All checks passed — no source mismatches or missing required packages.${RESET}"
|
|
else
|
|
echo -e "${RED}${BOLD}${ISSUES} issue(s) found — review items marked ✘ or ⚠ above.${RESET}"
|
|
# Only show the --fix hint if there are packages that can actually be auto-fixed
|
|
[ "$FIX" -eq 0 ] && [ $((${#WRONG_SOURCE_OFFICIAL[@]} + ${#WRONG_SOURCE_AUR[@]})) -gt 0 ] && \
|
|
echo -e "${YELLOW} Run with --fix to automatically reinstall wrong-source packages.${RESET}"
|
|
exit 1
|
|
fi
|