#! /bin/sh
# pkgpoke helper that wraps the apt-get calls pkgpoke is permitted to make
# via sudo. Restricts the surface area of the sudoers rule to "update" and
# "install <pkg>=<version>" with no other arguments or side-effects, so
# even if the wildcard in /etc/sudoers.d/pkgpoke matched something
# unexpected the wrapper itself would refuse to run it.
set -e

# Run apt non-interactively so the service never blocks waiting on a
# debconf prompt
export DEBIAN_FRONTEND=noninteractive

case "$1" in
    update)
        # No additional arguments allowed
        if [ "$#" -ne 1 ]; then
            echo "usage: pkgpoke-apt update" >&2
            exit 2
        fi
        exec /usr/bin/apt-get update
        ;;
    install)
        # Exactly one extra argument of the form pkg=version
        if [ "$#" -ne 2 ]; then
            echo "usage: pkgpoke-apt install <pkg>=<version>" >&2
            exit 2
        fi
        case "$2" in
            *=*) ;;
            *) echo "argument must be of the form pkg=version" >&2; exit 2 ;;
        esac
        # Layered validation: the Rust caller already validates characters,
        # but reject anything unexpected here too so the wrapper alone
        # cannot be used to smuggle metacharacters into apt-get.
        # LC_ALL=C ensures the character ranges match ASCII regardless of locale.
        if ! printf '%s\n' "$2" | LC_ALL=C grep -qxE '[a-z0-9][a-z0-9.+-]+=[A-Za-z0-9][A-Za-z0-9.+~:-]*'; then
            echo "invalid characters in pkg=version argument" >&2
            exit 2
        fi
        # --allow-downgrades so explicit version pins can move both
        # directions; --force-conf{old,def} keeps operator-modified config
        # files in place when packages with conffile prompts are installed
        exec /usr/bin/apt-get install -y \
            --allow-downgrades \
            -o "Dpkg::Options::=--force-confold" \
            -o "Dpkg::Options::=--force-confdef" \
            "$2"
        ;;
    *)
        echo "unknown subcommand: ${1:-<empty>}" >&2
        exit 2
        ;;
esac
