From cad75996b55a37a86e73f0d3bb4356c0035c8ec7 Mon Sep 17 00:00:00 2001 From: chrisfu Date: Sat, 9 May 2026 21:33:15 -0700 Subject: [PATCH] fix: set recovery password unconditionally after any admin token path The 1Password password-setting block was nested inside path 2 of promote_gitea_admin(). When path 1 found a cached gitea-admin-token k8s secret, path 2 was skipped entirely and the recovery password was never set in Gitea, leaving the user unable to log in. Move the password-setting step to run unconditionally after all four token paths complete. Uses _op_ensure_auth() so it degrades gracefully in CI/headless environments where 1Password is unavailable. Co-Authored-By: Claude Sonnet 4.6 --- etc/init_knoe_users.sh | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/etc/init_knoe_users.sh b/etc/init_knoe_users.sh index aaa03c1..1ed133f 100755 --- a/etc/init_knoe_users.sh +++ b/etc/init_knoe_users.sh @@ -1094,28 +1094,11 @@ promote_gitea_admin() { # 2. Bootstrap via the Helm admin account (k8s secret → REST API token). # This path works even when the gitea admin CLI is broken (app.ini has wrong # DB hostname) because REST calls go through the running server which has the - # correct GITEA__database__HOST env var. Once we have a bootstrap token, use - # it to also set KNOE_ADMIN_PRINCIPAL's password via API (from 1Password). + # correct GITEA__database__HOST env var. local _helm_token="" if [[ -z "$token" ]]; then if _helm_token=$(gitea_helm_admin_token "knoe-installer-helm"); then token="$_helm_token" - # Opportunistically set KNOE_ADMIN_PRINCIPAL's 1Password-backed password - # via REST so chrisfu can log in as fallback if SPNEGO is unavailable. - # 1Password is optional here — primary auth is Kerberos SPNEGO. - if command -v op >/dev/null 2>&1; then - local _pw="" - if _pw=$(gitea_ensure_password "${KNOE_ADMIN_PRINCIPAL}" 2>/dev/null); then - log "Gitea: setting password for '${KNOE_ADMIN_PRINCIPAL}' via admin REST API ..." - gitea_api_set_password "$_helm_token" "${KNOE_ADMIN_PRINCIPAL}" "$_pw" \ - && log "Gitea: password set for '${KNOE_ADMIN_PRINCIPAL}'" \ - || true - _pw="" - else - warn " Gitea: 1Password unavailable (op not signed in?) — skipping fallback password set" - warn " Run 'op signin' on $(hostname) and re-run to store recovery credentials" - fi - fi fi fi @@ -1162,6 +1145,24 @@ promote_gitea_admin() { return 0 fi + # Set KNOE_ADMIN_PRINCIPAL's recovery password unconditionally — regardless of + # which token path succeeded above. Primary auth is Kerberos SPNEGO; this gives + # every admin a 1Password-backed fallback for break-glass access. + # Skipped gracefully if op is unavailable (automated CI, no 1Password session). + if _op_ensure_auth 2>/dev/null; then + local _pw="" + if _pw=$(gitea_ensure_password "${KNOE_ADMIN_PRINCIPAL}" 2>/dev/null); then + log "Gitea: setting recovery password for '${KNOE_ADMIN_PRINCIPAL}' via admin REST API ..." + gitea_api_set_password "$token" "${KNOE_ADMIN_PRINCIPAL}" "$_pw" \ + && log "Gitea: recovery password set for '${KNOE_ADMIN_PRINCIPAL}'" \ + || true + _pw="" + else + warn " Gitea: 1Password unavailable (op not signed in?) — skipping fallback password set" + warn " Run 'op signin' on $(hostname) and re-run to store recovery credentials" + fi + fi + # Persist token in k8s secret for automation reuse (tokens are revocable) kubectl -n "$GITEA_NAMESPACE" create secret generic gitea-admin-token \ --from-literal=token="$token" \