#!/command/with-contenv sh
# shellcheck shell=sh
# Make supervise/ trees for ALL declared s6 services queryable and
# controllable by the unprivileged hermes user (UID 10000).
#
# Background (PR #30136 review item I4): the entire s6 lifecycle
# (s6-svc, s6-svstat, s6-svwait) is dispatched as the hermes user
# inside the container (every Hermes runtime path runs under
# ``s6-setuidgid hermes``). But s6-supervise creates each service's
# ``supervise/`` and top-level ``event/`` directory with mode 0700
# owned by its effective UID — which is root, because s6-supervise
# is spawned by s6-svscan running as PID 1. So unprivileged clients
# get EACCES on every probe / control call against the slot.
#
# Two fixes, one in each registration path:
#
# 1. For RUNTIME-registered profile gateways (created via the s6
#    runtime register hooks in profiles.py): the Python helper
#    ``_seed_supervise_skeleton`` pre-creates supervise/ + event/ +
#    supervise/control owned by hermes BEFORE s6-svscanctl -a fires.
#    s6-supervise's mkdir/mkfifo are EEXIST-safe, so it inherits our
#    ownership and never tries to chown back to root.
#
# 2. For STATIC s6-rc services (dashboard, main-hermes) declared at
#    image-build time under /etc/s6-overlay/s6-rc.d/*: these are
#    compiled by s6-rc at boot, and s6-supervise spawns BEFORE
#    cont-init.d gets to run — so by the time we're here, the
#    supervise/ tree is already there as root:root 0700. We chown
#    it here. s6-supervise will keep using the same files; it never
#    re-asserts ownership on a running service.
#
# This script runs as root after 01-hermes-setup but before
# 02-reconcile-profiles, so the chowns are settled before the
# Python reconciler walks the scandir. Lexicographic ordering
# guarantees this — the suffix is unusual because we want to slot
# in between 01 and the existing 02-reconcile-profiles without
# renumbering both (which would be a churn-noise patch on its own).

set -eu

# /run/s6-rc/servicedirs holds the live, compiled service directories
# for every static (s6-rc) service. Symlinks under /run/service/*
# point here. Per-service supervise/ + event/ both need hermes
# ownership for s6-svstat etc. to work as hermes.
SVC_ROOT=/run/s6-rc/servicedirs

if [ ! -d "$SVC_ROOT" ]; then
    echo "[supervise-perms] $SVC_ROOT not present; skipping"
    exit 0
fi

for svc in "$SVC_ROOT"/*; do
    [ -d "$svc" ] || continue
    name=$(basename "$svc")

    # Skip s6-overlay-internal services (they need to stay root-only;
    # the s6rc-* helpers manage the supervision tree itself).
    case "$name" in
        s6rc-*|s6-linux-*)
            continue
            ;;
    esac

    # supervise/ tree — needed by s6-svstat / s6-svc.
    if [ -d "$svc/supervise" ]; then
        chown -R hermes:hermes "$svc/supervise" 2>/dev/null || \
            echo "[supervise-perms] could not chown $svc/supervise"
        # 0710 = group searchable. ``s6-svstat`` only needs to openat
        # status, not list the dir, but giving the hermes group +x is
        # the minimum that lets group members access the contents.
        chmod 0710 "$svc/supervise" 2>/dev/null || true
        # supervise/control is a FIFO that s6-svc writes commands
        # into; the hermes user needs +w. Owner is already hermes
        # after the recursive chown above; widen perms to 0660 so
        # ``s6-svc`` works for any member of the hermes group too.
        if [ -p "$svc/supervise/control" ]; then
            chmod 0660 "$svc/supervise/control" 2>/dev/null || true
        fi
    fi

    # Top-level event/ dir — s6-svlisten1 / s6-svwait subscribe here.
    if [ -d "$svc/event" ]; then
        chown hermes:hermes "$svc/event" 2>/dev/null || \
            echo "[supervise-perms] could not chown $svc/event"
        # Preserve s6's 03730 mode (setgid + g+rwx + sticky).
        chmod 03730 "$svc/event" 2>/dev/null || true
    fi
done

echo "[supervise-perms] chowned supervise/ trees for static s6-rc services"
