Fix authentik-setup.sh: broken jget stdin handling, wrong stage path
Deploy to Dev / Deploy & Smoke Test (push) Successful in 24s

Two bugs found running this against the live Authentik instance for
the first time:

- jget's <<<"$1" here-string always overrode stdin, so `api ... | jget
  - "expr"` never actually read curl's piped output - it fed the
  literal string "-" to json.load() instead, and the abandoned pipe
  made curl fail with "Failed writing body". Fixed by branching on
  $1 == "-" to read the real stdin in that case.
- The prompt stage lives at /stages/prompt/stages/, not /stages/prompt/
  (that path is prompt *fields*). Wrong path 404'd.

Also switched `python` -> `python3` throughout for portability.

Verified idempotent end-to-end against auth.jerodrigged.com: provider,
application, lisilou-admin group, and the full enrollment flow
(prompt -> write -> login stages, bound and set as the brand's
enrollment flow) all created successfully, second run reports
everything as already existing.
This commit is contained in:
2026-07-20 06:15:41 +00:00
parent c97f1f73ce
commit 2f5607df82
+12 -6
View File
@@ -39,7 +39,13 @@ api() { # method path [json-body]
fi fi
} }
jget() { python -c "import sys,json;d=json.load(sys.stdin);print(eval(sys.argv[1]))" "$2" <<<"$1"; } jget() { # jget <json-string|-> <python-expr> ('-' reads JSON from stdin, e.g. a pipe)
if [ "$1" = "-" ]; then
python3 -c "import sys,json;d=json.load(sys.stdin);print(eval(sys.argv[1]))" "$2"
else
python3 -c "import sys,json;d=json.load(sys.stdin);print(eval(sys.argv[1]))" "$2" <<<"$1"
fi
}
echo "── Checking API access…" echo "── Checking API access…"
VERSION=$(api GET /admin/version/ | jget - "d['version_current']" 2>/dev/null || true) VERSION=$(api GET /admin/version/ | jget - "d['version_current']" 2>/dev/null || true)
@@ -54,7 +60,7 @@ SCOPES=$(api GET "/propertymappings/provider/scope/?managed__iexact=goauthentik.
for s in profile email; do for s in profile email; do
SCOPES="$SCOPES,$(api GET "/propertymappings/provider/scope/?managed__iexact=goauthentik.io/providers/oauth2/scope-$s" | jget - "d['results'][0]['pk']")" SCOPES="$SCOPES,$(api GET "/propertymappings/provider/scope/?managed__iexact=goauthentik.io/providers/oauth2/scope-$s" | jget - "d['results'][0]['pk']")"
done done
SCOPES_JSON=$(python -c "import sys;print(__import__('json').dumps(sys.argv[1].split(',')))" "$SCOPES") SCOPES_JSON=$(python3 -c "import sys;print(__import__('json').dumps(sys.argv[1].split(',')))" "$SCOPES")
# ── 2. OAuth2 provider ──────────────────────────────────────────────────────── # ── 2. OAuth2 provider ────────────────────────────────────────────────────────
echo "── Provider…" echo "── Provider…"
@@ -63,7 +69,7 @@ if [ "$EXISTING" -gt 0 ]; then
PROVIDER_PK=$(api GET "/providers/oauth2/?name=$CLIENT_ID" | jget - "d['results'][0]['pk']") PROVIDER_PK=$(api GET "/providers/oauth2/?name=$CLIENT_ID" | jget - "d['results'][0]['pk']")
echo " exists (pk=$PROVIDER_PK)" echo " exists (pk=$PROVIDER_PK)"
else else
BODY=$(python - "$AUTHZ_FLOW" "$INVALIDATION_FLOW" "$SCOPES_JSON" <<'PY' BODY=$(python3 - "$AUTHZ_FLOW" "$INVALIDATION_FLOW" "$SCOPES_JSON" <<'PY'
import json, sys import json, sys
authz, inval, scopes = sys.argv[1], sys.argv[2], json.loads(sys.argv[3]) authz, inval, scopes = sys.argv[1], sys.argv[2], json.loads(sys.argv[3])
p = { p = {
@@ -85,7 +91,7 @@ PY
) )
RESP=$(api POST /providers/oauth2/ "$BODY" 2>&1) || { RESP=$(api POST /providers/oauth2/ "$BODY" 2>&1) || {
# Older Authentik (<2024.2) wants redirect_uris as a newline-joined string # Older Authentik (<2024.2) wants redirect_uris as a newline-joined string
BODY=$(python -c " BODY=$(python3 -c "
import json,sys import json,sys
p=json.loads(sys.argv[1]); p['redirect_uris']='\n'.join(u['url'] for u in p['redirect_uris']); print(json.dumps(p))" "$BODY") p=json.loads(sys.argv[1]); p['redirect_uris']='\n'.join(u['url'] for u in p['redirect_uris']); print(json.dumps(p))" "$BODY")
RESP=$(api POST /providers/oauth2/ "$BODY") RESP=$(api POST /providers/oauth2/ "$BODY")
@@ -155,7 +161,7 @@ else
make_field password "Password" password 3 "" make_field password "Password" password 3 ""
make_field password_repeat "Confirm password" password 4 "" make_field password_repeat "Confirm password" password 4 ""
PROMPT_STAGE=$(api POST /stages/prompt/ "{ PROMPT_STAGE=$(api POST /stages/prompt/stages/ "{
\"name\": \"lisilou-enrollment-prompt\", \"name\": \"lisilou-enrollment-prompt\",
\"fields\": [\"${FIELD_PKS[username]}\",\"${FIELD_PKS[name]}\",\"${FIELD_PKS[email]}\",\"${FIELD_PKS[password]}\",\"${FIELD_PKS[password_repeat]}\"] \"fields\": [\"${FIELD_PKS[username]}\",\"${FIELD_PKS[name]}\",\"${FIELD_PKS[email]}\",\"${FIELD_PKS[password]}\",\"${FIELD_PKS[password_repeat]}\"]
}" | jget - "d['pk']") }" | jget - "d['pk']")
@@ -191,7 +197,7 @@ OIDC_CLIENT_ID=$CLIENT_ID
OIDC_CLIENT_SECRET=$CLIENT_SECRET OIDC_CLIENT_SECRET=$CLIENT_SECRET
OIDC_REDIRECT_URI=$PROD_REDIRECT OIDC_REDIRECT_URI=$PROD_REDIRECT
OIDC_ADMIN_GROUP=lisilou-admin OIDC_ADMIN_GROUP=lisilou-admin
SESSION_SECRET=$(openssl rand -hex 32 2>/dev/null || python -c "import secrets;print(secrets.token_hex(32))") SESSION_SECRET=$(openssl rand -hex 32 2>/dev/null || python3 -c "import secrets;print(secrets.token_hex(32))")
Then: docker compose restart api Then: docker compose restart api
EOF EOF