diff --git a/k8s/security/iam/scripts/authentik-provision.py b/k8s/security/iam/scripts/authentik-provision.py index fab4cfa..7373dcc 100644 --- a/k8s/security/iam/scripts/authentik-provision.py +++ b/k8s/security/iam/scripts/authentik-provision.py @@ -301,14 +301,21 @@ for name, cfg in SERVICES.items(): }, ) + # superuser_full_list=true is REQUIRED on the LIST: the applications list + # applies access-policy filtering to the results array (these apps are bound + # to homelab-admins, and the bootstrap-token user akadmin is not a member), + # so without it the GET returns an empty results list even though the app + # exists -> fall through to POST -> 400 "already exists". + # + # We deliberately do NOT patch_existing here: the application DETAIL endpoint + # (PATCH /applications/{pk}/) enforces the same access policy and does NOT + # honor superuser_full_list, so PATCH-by-pk returns 404 for akadmin once the + # homelab-admins binding exists. That 404 aborted the loop before later + # providers got their grant_types. slug/provider/launch_url are set at + # creation and are stable (provider is get_or_create'd by name, stable pk), + # so find-or-create is sufficient. application = get_or_create( "/api/v3/core/applications/", "/api/v3/core/applications/", - # superuser_full_list=true is REQUIRED: the applications list applies - # access-policy filtering to the results array (these apps are bound to - # homelab-admins, and the bootstrap-token user akadmin is not a member), - # so without it the GET returns an empty results list even though the app - # exists -> get_or_create falls through to POST -> 400 "already exists", - # which aborted the whole loop before later providers got grant_types. f"slug={name}&superuser_full_list=true", { "name": cfg["display_name"], @@ -316,10 +323,6 @@ for name, cfg in SERVICES.items(): "provider": provider["pk"], "meta_launch_url": cfg["launch_url"], }, - patch_existing={ - "provider": provider["pk"], - "meta_launch_url": cfg["launch_url"], - }, ) app_pks_for_binding.append((name, application["pk"])) print(f" {name}: provider pk={provider['pk']} application pk={application['pk']}")