# driveripper-ops sudo rules for the UPS dashboard work
#
# Install as /etc/sudoers.d/dashboards-nut (visudo -cf it first):
#
#   sudo visudo -cf - <<'EOF' ... EOF     # syntax check
#   install -m 0440 deploy/nut-sudoers /tmp/dashboards-nut
#   sudo mv /tmp/dashboards-nut /etc/sudoers.d/dashboards-nut
#
# Keep it scoped: paths are absolute (sudoers uses `secure_path`), arguments are wildcards
# only where the command is read-only or idempotent, and nothing here allows a shell,
# `EDITOR=`, `dnf install` of arbitrary code, or `upsd -c` with an attacker-chosen file.

# ---- already present on driveripper (this is what the dashboard setup used) ---------- #
# (root) NOPASSWD: /usr/bin/tee /etc/ups/*                  # write upsd.conf / upsd.users
# (root) NOPASSWD: /usr/bin/cp /etc/ups/* /home/ops/*       # back up a config before editing
# (root) NOPASSWD: /usr/bin/systemctl start|restart|reload|enable *
# (root) NOPASSWD: /usr/bin/udevadm *                       # USB device discovery/replug
# (root) NOPASSWD: /usr/bin/firewall-cmd *                  # only if upsd must serve the LAN
# (root) NOPASSWD: /usr/bin/dnf install *                   # nut, nut-client, nut-dev

# ---- still needed: diagnose why upsd runs but binds nothing -------------------------- #
# Reading is the blocker. `upsd` is active, both drivers are up, and 3493 has no listener,
# but /etc/ups/* is 0640 root:nut and the journal needs group membership:
#   $ sudo cat /etc/ups/upsd.conf            -> Permission denied
#   $ journalctl -u nut-server -n 50         -> No entries (not in systemd-journal/wheel)
#   $ upsc -l                                -> Error: Connection failure: Connection refused

Cmnd_Alias NUT_DIAGNOSE = \
    /usr/bin/cat /etc/ups/*, \
    /usr/bin/systemctl status *, \
    /usr/bin/journalctl -u nut-server *, /usr/bin/journalctl -u nut-driver@*, \
    /usr/bin/journalctl -u nut*, \
    /usr/sbin/ss -ltnp, \
    /usr/sbin/getenforce, \
    /usr/bin/ausearch *, /usr/sbin/sealert -l *, \
    /usr/sbin/semanage port -l, \
    /usr/bin/upsdrvctl status, /usr/bin/upsdrvctl status *, \
    /usr/bin/upsc *, \
    /usr/bin/lsusb

# ---- still needed: apply the fix and verify ------------------------------------------ #
# `tee /etc/ups/*` already writes configs; these cover the reload path, SELinux booleans,
# and a bounded cleanup of the .bak files `tee`-based edits leave behind.
Cmnd_Alias NUT_APPLY = \
    /usr/bin/tee /etc/ups/upsd.conf, /usr/bin/tee /etc/ups/upsd.users, \
    /usr/bin/tee /etc/ups/ups.conf, /usr/bin/tee /etc/ups/nut.conf, \
    /usr/bin/rm -f /etc/ups/*.bak-*, \
    /usr/bin/upsdrvctl restart, /usr/bin/upsdrvctl restart *, \
    /usr/sbin/setsebool -P allow_upsd_tcp_server 1, \
    /usr/sbin/setsebool -P nis_enabled 0

# NOTE: deliberately NOT allowed, so an agent cannot power-cycle anything by accident:
#   /usr/bin/upscmd (any form) — the dashboard's own gated POST is the only command path
#   systemctl stop *           — stopping nut-server would blind the UPS view
#   editors, shells, `sh -c`                                             — no escape hatches
