#! /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
        # Defense-in-depth: 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
        if ! printf '%s\n' "$2" | grep -qxE '\[a-z0-9\]\[a-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
