diff --git a/.SRCINFO b/.SRCINFO index df66b26..dc95c6f 100644 --- a/.SRCINFO +++ b/.SRCINFO @@ -1,7 +1,7 @@ pkgbase = grok-bot-bin pkgdesc = Grok Bot desktop agent (official .deb repackaged) pkgver = 0.39.0 - pkgrel = 1 + pkgrel = 2 url = https://cursor.com/download/bot arch = x86_64 license = LicenseRef-proprietary @@ -19,6 +19,7 @@ pkgbase = grok-bot-bin depends = xdg-utils optdepends = libappindicator-gtk3: tray icon support optdepends = curl: auto-update check on launch + optdepends = polkit: graphical password prompt for desktop auto-update (pkexec) provides = grok-bot provides = sand conflicts = grok-bot @@ -28,8 +29,12 @@ pkgbase = grok-bot-bin options = !debug source = https://downloads.cursor.com/grokbot/stable/d8bc9c753edddb313047c9c69b480b7f8f321087/linux/x64/grok-bot_0.39.0_amd64.deb source = grok-bot-launch.sh + source = pkexec-pacman-u + source = com.s1d3sw1ped.grok-bot-bin.policy noextract = grok-bot_0.39.0_amd64.deb sha256sums = ae498adaf71f9ff1734a786163c5807fa50165acb5aa102bb68f43ead96de4fe - sha256sums = 1c5a3599db15816caa839fc9e088ba9798757e44fec89c066ef5f6f3c0972aee + sha256sums = 36e1c522f7a3920a850a6235263d82ad5990611612979447c1e9eff92548ac1e + sha256sums = e92ea4534d864d7f302a082a8717a52af9675195af41092d18f15094f74fed45 + sha256sums = a9533dfe4d31332ac1505d2e582eff27771dd0107108a5f6289d0d3839431a74 pkgname = grok-bot-bin diff --git a/PKGBUILD b/PKGBUILD index 1dd4a0a..07309fe 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -10,7 +10,7 @@ pkgname=grok-bot-bin pkgver=0.39.0 _commit=d8bc9c753edddb313047c9c69b480b7f8f321087 -pkgrel=1 +pkgrel=2 pkgdesc="Grok Bot desktop agent (official .deb repackaged)" arch=('x86_64') url="https://cursor.com/download/bot" @@ -32,6 +32,7 @@ depends=( optdepends=( 'libappindicator-gtk3: tray icon support' 'curl: auto-update check on launch' + 'polkit: graphical password prompt for desktop auto-update (pkexec)' ) provides=('grok-bot' 'sand') conflicts=('grok-bot' 'sand') @@ -40,11 +41,15 @@ options=('!strip' '!debug') source=( "https://downloads.cursor.com/grokbot/stable/${_commit}/linux/x64/grok-bot_${pkgver}_amd64.deb" "grok-bot-launch.sh" + "pkexec-pacman-u" + "com.s1d3sw1ped.grok-bot-bin.policy" ) noextract=("grok-bot_${pkgver}_amd64.deb") sha256sums=( 'ae498adaf71f9ff1734a786163c5807fa50165acb5aa102bb68f43ead96de4fe' - '1c5a3599db15816caa839fc9e088ba9798757e44fec89c066ef5f6f3c0972aee' + '36e1c522f7a3920a850a6235263d82ad5990611612979447c1e9eff92548ac1e' + 'e92ea4534d864d7f302a082a8717a52af9675195af41092d18f15094f74fed45' + 'a9533dfe4d31332ac1505d2e582eff27771dd0107108a5f6289d0d3839431a74' ) package() { @@ -56,6 +61,11 @@ package() { # Keep provides(sand) on PATH; both names run the same shim. ln -sf grok-bot "$pkgdir/usr/bin/sand" + # pkexec helper + polkit action (auth_admin, not NOPASSWD) for desktop auto-update. + install -Dm755 "$srcdir/pkexec-pacman-u" "$pkgdir/usr/lib/grok-bot-bin/pkexec-pacman-u" + install -Dm644 "$srcdir/com.s1d3sw1ped.grok-bot-bin.policy" \ + "$pkgdir/usr/share/polkit-1/actions/com.s1d3sw1ped.grok-bot-bin.policy" + # Always point the menu entry at the PATH shim. Upstream .desktop has used # Exec="/opt/Grok Bot/grok-bot" (0.30) which bypasses auto-update; rewrite # every build so a future /opt regression cannot ship again. diff --git a/README.md b/README.md index 474516b..8f2e5c9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Not affiliated with Cursor / SpaceXAI. The app binary is unchanged; this only re ## Install (build locally) -This tree packages **0.39.0** (`pkgver` / `pkgrel=1` in `PKGBUILD`). `makepkg -si` from git tip builds that version even before a release tag exists. +This tree packages **0.39.0** (`pkgver` / `pkgrel=2` in `PKGBUILD`). `makepkg -si` from git tip builds that version even before a release tag exists. ```bash git clone https://git.s1d3sw1ped.com/s1d3sw1ped/grok-bot-bin.git @@ -53,7 +53,7 @@ Exact `Server=` URL may change once the first repo DB lands; `makepkg -si` works ## Updating -Stay-current path when Cursor's linux-x64 Grok Bot feed moves. `PKGBUILD` is currently **0.39.0** (pkgrel 1). One updater: `./scripts/update.sh`. +Stay-current path when Cursor's linux-x64 Grok Bot feed moves. `PKGBUILD` is currently **0.39.0** (pkgrel 2). One updater: `./scripts/update.sh`. ### Scheduled bump (Gitea Actions) @@ -100,6 +100,8 @@ Install the new version with `makepkg -si`, or (once CI publishes the asset) `pa ## Notes - `/usr/bin/grok-bot` (and `sand`) is a launch shim: unless `GROK_BOT_NO_UPDATE=1`, it checks the latest Gitea release and may `pacman -U` a newer `.pkg.tar.zst` before exec'ing `/opt/Grok Bot/…`. Network/API failures still launch the installed binary. +- Auto-update privilege order: `sudo -n` (passwordless, e.g. lab NOPASSWD) → `pkexec` / polkit when launched from the desktop (no TTY, `DISPLAY` or `WAYLAND_DISPLAY` set) → interactive `sudo` when stdin is a TTY. Cancel or deny still launches the installed binary. Passwordless sudo is **not** the default. +- Desktop / CachyOS: `polkit` (provides `pkexec`) and a session polkit authentication agent (usually already running with KDE / GNOME / Hyprland / etc.) are required for the graphical password prompt. The package installs `/usr/lib/grok-bot-bin/pkexec-pacman-u` and `com.s1d3sw1ped.grok-bot-bin.update` (`auth_admin`, not NOPASSWD). `polkit` is an optdepend. - If the app menu still launches an old binary without updating, run `/usr/bin/grok-bot` once from a terminal, or `sudo pacman -U` the newer `.pkg.tar.zst` from Releases — the menu must call the PATH shim, not `/opt/Grok Bot/…`. - Upstream Linux builds still have no in-app updater for the Electron app itself; `scripts/update.sh` (cron or manual) is the packaging bump from Cursor's feed. - `chrome-sandbox` is left non-setuid because the install path contains a space; user namespaces cover sandboxing on CachyOS. diff --git a/com.s1d3sw1ped.grok-bot-bin.policy b/com.s1d3sw1ped.grok-bot-bin.policy new file mode 100644 index 0000000..e46109f --- /dev/null +++ b/com.s1d3sw1ped.grok-bot-bin.policy @@ -0,0 +1,18 @@ + + + + s1d3sw1ped + https://git.s1d3sw1ped.com/s1d3sw1ped/grok-bot-bin + + Install a grok-bot-bin package update + Authentication is required to update Grok Bot + + no + no + auth_admin + + /usr/lib/grok-bot-bin/pkexec-pacman-u + + diff --git a/grok-bot-launch.sh b/grok-bot-launch.sh index 8eb6e5a..0f3cf23 100755 --- a/grok-bot-launch.sh +++ b/grok-bot-launch.sh @@ -5,6 +5,43 @@ set -u REAL_DIR="/opt/Grok Bot" API_URL='https://git.s1d3sw1ped.com/api/v1/repos/s1d3sw1ped/grok-bot-bin/releases?limit=1' +PKEXEC_HELPER=/usr/lib/grok-bot-bin/pkexec-pacman-u + +# Privilege order for pacman -U: +# 1. sudo -n (NOPASSWD, e.g. lab CT113) +# 2. pkexec (graphical polkit; desktop Exec=grok-bot has no TTY) +# 3. interactive sudo (terminal TTY) +# Never default to passwordless sudo. Cancel/deny still launches the installed binary. +_install_update_pkg() { + local pkg=$1 + + if sudo -n true 2>/dev/null; then + if sudo -n pacman -U --noconfirm "$pkg"; then + return 0 + fi + echo "grok-bot: pacman -U failed; launching installed version" >&2 + return 1 + fi + + if [[ ! -t 0 ]] && command -v pkexec >/dev/null 2>&1 && [[ -x "$PKEXEC_HELPER" ]] \ + && [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]]; then + if pkexec --disable-internal-agent "$PKEXEC_HELPER" "$pkg"; then + return 0 + fi + echo "grok-bot: polkit auth failed or cancelled; launching installed version" >&2 + return 1 + fi + + if [[ -t 0 ]]; then + if sudo pacman -U --noconfirm "$pkg"; then + return 0 + fi + fi + + echo "grok-bot: need sudo or polkit to auto-update; run: sudo pacman -U or launch /usr/bin/grok-bot from a terminal" >&2 + echo "grok-bot: pacman -U failed; launching installed version" >&2 + return 1 +} _maybe_update() { [[ "${GROK_BOT_NO_UPDATE:-}" == "1" ]] && return 0 @@ -50,14 +87,7 @@ _maybe_update() { return 0 fi - # Prefer passwordless sudo; fall back to interactive sudo. Fail soft either way. - if ! sudo -n pacman -U --noconfirm "$pkg" 2>/dev/null; then - if ! sudo pacman -U --noconfirm "$pkg"; then - echo "grok-bot: need sudo to auto-update; run: sudo pacman -U or launch /usr/bin/grok-bot from a terminal" >&2 - echo "grok-bot: pacman -U failed; launching installed version" >&2 - return 0 - fi - fi + _install_update_pkg "$pkg" || return 0 } _maybe_update || true diff --git a/pkexec-pacman-u b/pkexec-pacman-u new file mode 100755 index 0000000..ab3b43e --- /dev/null +++ b/pkexec-pacman-u @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Root helper for grok-bot-bin GUI auto-update. Invoked via pkexec only. +# Runs pacman -U on a local grok-bot-bin package — not a generic pacman wrapper. +set -euo pipefail + +if [[ $# -ne 1 ]]; then + echo "pkexec-pacman-u: usage: pkexec-pacman-u /path/to/grok-bot-bin-*-x86_64.pkg.tar.zst" >&2 + exit 2 +fi + +pkg=$1 +if [[ "$pkg" != /* || "$pkg" == *..* ]]; then + echo "pkexec-pacman-u: refusing path: $pkg" >&2 + exit 2 +fi + +base=$(basename -- "$pkg") +if [[ ! "$base" =~ ^grok-bot-bin-.+-x86_64\.pkg\.tar\.zst$ ]]; then + echo "pkexec-pacman-u: refusing package name: $base" >&2 + exit 2 +fi + +if [[ ! -f "$pkg" || ! -r "$pkg" ]]; then + echo "pkexec-pacman-u: package not found or unreadable: $pkg" >&2 + exit 2 +fi + +# Filename is not enough; require the package metadata name. +info=$(/usr/bin/pacman -Qp -- "$pkg" 2>/dev/null) || { + echo "pkexec-pacman-u: not a pacman package: $pkg" >&2 + exit 2 +} +name=${info%% *} +if [[ "$name" != grok-bot-bin ]]; then + echo "pkexec-pacman-u: refusing package $name" >&2 + exit 2 +fi + +exec /usr/bin/pacman -U --noconfirm -- "$pkg"