From 14521d37d3d0ceec13642071642355c41e1001e0 Mon Sep 17 00:00:00 2001 From: Keith Jackson Date: Thu, 27 Aug 2026 20:18:51 -0500 Subject: [PATCH] fix(nextcloud-sso): apply step-(d) retry hardening at SOURCE (catalog) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apps/wave-1/nextcloud.yaml is GENERATED from catalog/nextcloud.yaml by catalog/render.py, so the previous commit hardened only the rendered golden — the next render would have reverted step (d) to the old single-pass version. Apply the same verify-and-retry hardening to the postStart hook in catalog/nextcloud.yaml (the source of truth). Re-rendered with `render.py --all catalog -o apps --wave-layout`; apps/wave-1/nextcloud.yaml is byte-identical to the golden committed in the previous commit (render round-trip clean), so no apps/ change is needed here. Co-Authored-By: Claude Opus 4.8 --- catalog/nextcloud.yaml | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/catalog/nextcloud.yaml b/catalog/nextcloud.yaml index d320fcc..f28aba1 100644 --- a/catalog/nextcloud.yaml +++ b/catalog/nextcloud.yaml @@ -167,13 +167,31 @@ lifecycle: # ` once). The LOCAL break-glass admin is unaffected (docs/15). The group name is # passed to php as argv (never interpolated) so group:list JSON parses robustly. ADMIN_SRC_GROUP=platform-admins - admin_members=$(su -s /bin/sh www-data -c "php /var/www/html/occ group:list --output=json" 2>/dev/null \ - | php -r '$d=json_decode(stream_get_contents(STDIN),true);$g=$argv[1];if(is_array($d)&&!empty($d[$g])&&is_array($d[$g])){foreach($d[$g] as $u){echo $u,"\n";}}' -- "$ADMIN_SRC_GROUP" 2>/dev/null) - for uid in $admin_members; do - if OCC group:adduser admin "$uid" >/dev/null 2>&1; then - echo "[nextcloud-oidc] ensured '$uid' is a Nextcloud admin (member of $ADMIN_SRC_GROUP)" - fi + # HARDENED (verify-and-retry, like step (c)): the previous single pass ran `occ group:adduser` + # exactly once with its output swallowed (>/dev/null 2>&1) and NO retry, so an early-boot + # transient failure (DB / maintenance race in the first seconds after container start) silently + # dropped the promotion until the NEXT pod restart. This loop re-reads group:list and re-adds + # any platform-admins member still missing from 'admin' until all are verified (bounded ~30s); + # it is a no-op for members already in 'admin'. Group names are passed to php as argv (never + # interpolated) so the JSON parses robustly. + parse_group() { su -s /bin/sh www-data -c "php /var/www/html/occ group:list --output=json" 2>/dev/null | php -r '$d=json_decode(stream_get_contents(STDIN),true);$g=$argv[1];if(is_array($d)&&!empty($d[$g])&&is_array($d[$g])){foreach($d[$g] as $u){echo $u,"\n";}}' -- "$1" 2>/dev/null; } + p=0 + while [ "$p" -lt 15 ]; do + current_admins=$(parse_group admin) + missing=0 + for uid in $(parse_group "$ADMIN_SRC_GROUP"); do + if printf '%s\n' "$current_admins" | grep -qxF -- "$uid"; then + continue + fi + missing=1 + if OCC group:adduser admin "$uid" >/dev/null 2>&1; then + echo "[nextcloud-oidc] ensured '$uid' is a Nextcloud admin (member of $ADMIN_SRC_GROUP)" + fi + done + [ "$missing" = 0 ] && break + p=$((p + 1)); sleep 2 done + [ "$p" -ge 15 ] && nextcloud_oidc_fail "could not promote all $ADMIN_SRC_GROUP members into 'admin' after retries" exposure: public # edge port-forward + public DNS (docs/09; R-DNS/R-NET) egress: internet # normal WAN egress (docs/03; R-NET-05) — app store, integrity checks storage: