#!/usr/bin/env bash # No settings page may hand off to a GNOME panel that Panama itself owns. # # Panama absorbed Users, Sharing, Printers, Online Accounts and others one page # at a time. Each time, the rows pointing at GNOME's equivalent stayed where # they were -- so a settings app whose stated purpose is to make GNOME Settings # unnecessary shipped four separate doors back to it, two of them inside a card # headed "these areas remain owned by Fedora". # # Nothing failed. Every row worked exactly as written. The rows were simply no # longer true, and no test could notice because none of them knew what Panama # had come to own in the meantime. # # This reads SettingsRoutes for the pages that exist and the pages for the # panels they hand off, and fails on any overlap. It is deliberately derived # from both sides rather than from a hand-kept list, so absorbing the next page # cannot leave a stale door behind. # # Read-only. set -uo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" settings_dir="$repo_dir/config/dot/quickshell/modules/settings" routes="$repo_dir/config/dot/quickshell/services/SettingsRoutes.qml" fail() { printf 'gnome handoff contract: %s\n' "$1" >&2 exit 1 } [[ -r "$routes" ]] || fail "missing $routes" # GNOME panel names that correspond to a Panama page. Only entries whose panel # genuinely duplicates a Panama page belong here. # # "network" and "wifi" were deliberately kept off this list, on the reason that # Panama had no VPN and no per-connection routing, so GNOME's panel really did # do more. That stopped being true: Connections now carries per-connection # details, forget, autoconnect, MAC randomization, a VPN list with import, a # hotspot, enterprise Wi-Fi, airplane mode and the system proxy. The two rows # that pointed at GNOME were the last thing on that page telling the user to go # somewhere else for something it does, so both panels moved here and the rows # went with them. # # "online-accounts" is listed because Panama has an Online Accounts page -- but # adding an account still has to go through GOA's own dialog, so that one # exception is named explicitly below. # "privacy" joined the list when Privacy & Security stopped being a page that # read the portal and pointed at GNOME for everything else. It now clears the # recent-files list and the thumbnail cache itself, empties the trash through # Storage's own cleanable, and revokes portal grants for six tables rather than # three devices. The card that used to carry the door -- headed "Owned by # Fedora", explaining that GNOME's file-history switches would not take effect # in a Hyprland session anyway -- is gone, because the switches it was # apologizing for are now buttons that work. declare -A OWNED=( [network]=connectivity [wifi]=connectivity [printers]=printers [online-accounts]=accounts [sharing]=sharing [users]=users [system\ users]=users [privacy]=privacy ) # Handoffs that are correct despite naming an owned panel, with the reason. # Anything here must be justified, not merely tolerated. # # The Users entry is gone: fingerprint enrollment was the only thing sending # people to GNOME's Users panel, and Panama drives fprintd's EnrollStart itself # now, so the door has nothing behind it. fingerprint-contract pins the # inverse -- that the page does NOT open a GNOME panel. declare -A ALLOWED=( ["OnlineAccountsPage.qml:online-accounts"]="OAuth sign-in (Google, Microsoft) runs inside libgoa-backend, which Fedora ships without a GIR binding, so the provider's own dialog is the only way to obtain the token; Nextcloud and IMAP are added on the page itself" ) # The leaves: a tabless category is a page in its own right, and every tab is # a page. A category that only groups tabs owns no controls itself, so it is # not something GNOME could be handing a duplicate of. pages="$( { grep -oE '\{ page: "[a-z-]+", label: "[^"]*", icon: "[^"]*", tabs: \[\] \}' "$routes" grep -oE '\{ page: "[a-z-]+", label: "[^"]*" \}' "$routes" } | sed -E 's/\{ page: "([a-z-]+)".*/\1/' | sort -u)" [[ -n "$pages" ]] || fail 'no pages could be read from SettingsRoutes, so this proves nothing' has_page() { grep -qx "$1" <<<"$pages" } violations=0 checked=0 while IFS= read -r hit; do file="${hit%%:*}" base="$(basename "$file")" # openGnomePanel("a") or openGnomePanel("a", "b") -> "a" / "a b" panel="$(sed -E 's/.*openGnomePanel\("([^"]+)"(, *"([^"]+)")?\).*/\1 \3/' <<<"$hit" \ | sed 's/ *$//')" [[ -n "$panel" ]] || continue checked=$((checked + 1)) owner="${OWNED[$panel]:-}" [[ -n "$owner" ]] || continue has_page "$owner" || continue key="$base:${panel// /-}" if [[ -n "${ALLOWED[$key]:-}" ]]; then continue fi printf 'gnome handoff contract: %s hands "%s" to GNOME, but Panama owns the "%s" page\n' \ "$base" "$panel" "$owner" >&2 violations=$((violations + 1)) done < <(grep -rno --include='*.qml' -E 'openGnomePanel\("[^"]*"(, *"[^"]*")?\)' "$settings_dir") (( checked > 0 )) || fail 'no handoffs were examined, so this proves nothing' # The inverse, for the page that just stopped handing anything over. The loop # above can only fail on a door that exists; said this way it also fails if the # door comes back under a panel name nobody thought to list. if grep -q 'openGnomePanel' "$settings_dir/PrivacyPage.qml"; then printf 'gnome handoff contract: PrivacyPage still opens a GNOME panel:\n' >&2 grep -n 'openGnomePanel' "$settings_dir/PrivacyPage.qml" >&2 violations=$((violations + 1)) fi if (( violations > 0 )); then printf 'Each of these sends someone to GNOME for a page this app already has.\n' >&2 exit 1 fi printf 'gnome handoff contract: ok (%d handoffs checked against %d pages)\n' \ "$checked" "$(wc -l <<<"$pages")"