keycloak_admin_token() { kube --namespace "$FIXTURE_NAMESPACE" exec deployment/keycloak -- \ sh -ec ' /opt/keycloak/bin/kcadm.sh config credentials \ --server http://127.0.0.1:8080 \ --realm master \ --user nuthatch-admin \ --password synthetic-keycloak >/dev/null /opt/keycloak/bin/kcadm.sh get serverinfo >/dev/null ' >/dev/null } provision_lane_keycloak_registration() { local lane="$1" local redirect_uri="$2" local client_id_var="$3" local client_secret_var="$4" local additional_audiences_var="$5" local user_a_var="$6" local user_b_var="$7" local client_id="nuthatch-$lane" local client_secret="synthetic-keycloak-client-secret-$lane" local username keycloak_admin_token || return kube --namespace "$FIXTURE_NAMESPACE" exec deployment/keycloak -- \ /opt/keycloak/bin/kcadm.sh create clients \ --realm master \ -s "clientId=$client_id" \ -s enabled=true \ -s protocol=openid-connect \ -s publicClient=false \ -s clientAuthenticatorType=client-secret \ -s standardFlowEnabled=true \ -s directAccessGrantsEnabled=false \ -s "secret=$client_secret" \ -s "redirectUris=[\"$redirect_uri\"]" \ -s 'attributes={"pkce.code.challenge.method":"S256"}' >/dev/null || return for username in "nuthatch-$lane-a" "nuthatch-$lane-b"; do kube --namespace "$FIXTURE_NAMESPACE" exec deployment/keycloak -- \ /opt/keycloak/bin/kcadm.sh create users \ --realm master \ -s "username=$username" \ -s enabled=true \ -s "firstName=$username" >/dev/null || return kube --namespace "$FIXTURE_NAMESPACE" exec deployment/keycloak -- \ /opt/keycloak/bin/kcadm.sh set-password \ --realm master \ --username "$username" \ --new-password Synthetic-OIDC-1! >/dev/null || return done printf -v "$client_id_var" '%s' "$client_id" printf -v "$client_secret_var" '%s' "$client_secret" printf -v "$additional_audiences_var" '' printf -v "$user_a_var" '%s' "nuthatch-$lane-a" printf -v "$user_b_var" '%s' "nuthatch-$lane-b" } zitadel_api() { local token_path="$1" local method="$2" local path="$3" local body="$4" kube --namespace "$FIXTURE_NAMESPACE" exec \ deployment/zitadel \ --container oidc-provisioner \ -- sh -ec ' token="$(tr -d "\r\n" < "$1")" curl --fail --silent --show-error \ --request "$2" \ --header "Host: zitadel.nuthatch.test" \ --header "Authorization: Bearer $token" \ --header "Content-Type: application/json" \ --data "$4" \ "http://127.0.0.1:8080$3" ' sh "$token_path" "$method" "$path" "$body" } provision_lane_zitadel_registration() { local lane="$1" local redirect_uri="$2" local client_id_var="$3" local client_secret_var="$4" local additional_audiences_var="$5" local user_a_var="$6" local user_b_var="$7" local project_response local project_id local app_response local client_id local client_secret local username local user_response local user_ids=() project_response="$( zitadel_api \ /bootstrap/admin.pat \ POST \ /management/v1/projects \ "{\"name\":\"Nuthatch lane $lane\"}" )" || return project_id="$(jq -er .id <<< "$project_response")" || return app_response="$( zitadel_api \ /bootstrap/admin.pat \ POST \ "/management/v1/projects/$project_id/apps/oidc" \ "{\"projectId\":\"$project_id\",\"name\":\"Nuthatch lane $lane\",\"redirectUris\":[\"$redirect_uri\"],\"responseTypes\":[\"OIDC_RESPONSE_TYPE_CODE\"],\"grantTypes\":[\"OIDC_GRANT_TYPE_AUTHORIZATION_CODE\"],\"appType\":\"OIDC_APP_TYPE_WEB\",\"authMethodType\":\"OIDC_AUTH_METHOD_TYPE_BASIC\",\"version\":\"OIDC_VERSION_1_0\",\"devMode\":false}" )" || return client_id="$(jq -er .clientId <<< "$app_response")" || return client_secret="$(jq -er .clientSecret <<< "$app_response")" || return for username in "nuthatch-$lane-a" "nuthatch-$lane-b"; do user_response="$( zitadel_api \ /bootstrap/admin.pat \ POST \ /management/v1/users/human \ "{\"userName\":\"$username\",\"profile\":{\"firstName\":\"Nuthatch\",\"lastName\":\"$username\",\"displayName\":\"$username\",\"preferredLanguage\":\"en\"},\"email\":{\"email\":\"$username@example.test\",\"isEmailVerified\":true},\"initialPassword\":\"Synthetic-OIDC-1!\"}" )" || return user_ids+=("$(jq -er .userId <<< "$user_response")") || return done printf -v "$client_id_var" '%s' "$client_id" printf -v "$client_secret_var" '%s' "$client_secret" printf -v "$additional_audiences_var" '%s' "$project_id" printf -v "$user_a_var" '%s' "${user_ids[0]}" printf -v "$user_b_var" '%s' "${user_ids[1]}" } create_oidc_automation_secret() { local lane="$1" local provider="$2" local login_pat=unused if [[ "$provider" = zitadel ]]; then login_pat="$( kube --namespace "$FIXTURE_NAMESPACE" exec \ deployment/zitadel \ --container oidc-provisioner \ -- sh -ec 'tr -d "\r\n" < /bootstrap/login-client.pat' )" || return fi kube create secret generic "nuthatch-oidc-automation-$lane" \ --namespace "$FIXTURE_NAMESPACE" \ --from-literal="NUTHATCH_OIDC_LOGIN_PAT=$login_pat" \ --dry-run=client \ --output yaml | kube apply --filename - >/dev/null }