#!/usr/bin/env bash # lasuite-meet — INSTALL-TIME OIDC wiring hook (Phase 2 Q3.3; sibling of lasuite-drive's). # # Runs during the install tier AFTER `abra app new` + EXTRA_ENV + `abra app secret generate`, and # BEFORE the single `abra app deploy` (lifecycle.py::_run_install_steps). Writing OIDC env + the real # client secret HERE means the recipe deploys ONCE with OIDC already wired — no post-deploy reconverge # (OIDC_AT_INSTALL). The orchestrator provisions the per-run realm/client on the live-warm keycloak # BEFORE this hook and writes $CCCI_DEPS_FILE (the recipe→creds dict). # # Meet's OIDC is REQUIRED (recipe README). Same La Suite/impress env contract as drive, with meet's # client (OIDC_RP_CLIENT_ID = the per-run keycloak client = "lasuite-meet") and scopes "openid email". # # Env supplied by the harness: # CCCI_APP_DOMAIN — the per-run lasuite-meet app domain # CCCI_APP_ENV — path to the app's .env (the one `abra app deploy` reads) # CCCI_DEPS_FILE — JSON {keycloak: {domain, realm, client_id, client_secret, ...}} (may be empty) set -euo pipefail : "${CCCI_APP_DOMAIN:?missing}" ENV_PATH="${CCCI_APP_ENV:?missing}" # No deps file / no keycloak entry → install-time provisioning failed or was skipped. NO-OP so the # recipe still boots; the @requires_deps OIDC custom test then SKIPs and F2-11 flips the run RED. if [ -z "${CCCI_DEPS_FILE:-}" ] || [ ! -s "${CCCI_DEPS_FILE}" ]; then echo " install_steps: no deps file — skipping OIDC wiring (recipe boots without OIDC)" exit 0 fi KC_DOMAIN=$(jq -r '.keycloak.domain // empty' "$CCCI_DEPS_FILE") KC_REALM=$( jq -r '.keycloak.realm // empty' "$CCCI_DEPS_FILE") KC_CLIENT=$(jq -r '.keycloak.client_id // empty' "$CCCI_DEPS_FILE") KC_SECRET=$(jq -r '.keycloak.client_secret // empty' "$CCCI_DEPS_FILE") if [ -z "$KC_DOMAIN" ] || [ -z "$KC_SECRET" ]; then echo " install_steps: deps file has no keycloak domain/secret — skipping OIDC wiring" exit 0 fi echo " lasuite-meet install_steps: wiring OIDC at install against keycloak ${KC_DOMAIN}" # 1) Insert the OIDC client secret at a bumped version (abra already generated oidc_rpcs:v1; swarm # forbids overwriting a secret at the same version). The app is not deployed yet — a swarm secret can # be created independently — so the single deploy below picks up v2. CUR_VER=$(grep -E '^\s*SECRET_OIDC_RPCS_VERSION=' "$ENV_PATH" | tail -1 | cut -d= -f2 | tr -d '"\r' || echo "v1") NEW_NUM=$(( ${CUR_VER#v} + 1 )) NEW_VER="v${NEW_NUM}" INSERT_LOG=$(abra app secret insert "$CCCI_APP_DOMAIN" oidc_rpcs "$NEW_VER" "$KC_SECRET" --no-input 2>&1) \ || INSERT_LOG=$(script -qec "abra app secret insert $CCCI_APP_DOMAIN oidc_rpcs $NEW_VER $KC_SECRET --no-input" /dev/null 2>&1) \ || { echo " install_steps: abra app secret insert oidc_rpcs@$NEW_VER failed: $INSERT_LOG"; exit 1; } sed -i "s|^\s*SECRET_OIDC_RPCS_VERSION=.*|SECRET_OIDC_RPCS_VERSION=$NEW_VER|" "$ENV_PATH" echo " install_steps: oidc_rpcs secret inserted at $NEW_VER (was $CUR_VER)" # 2) Write the OIDC env vars (explicit endpoints — deterministic). Meet's .env.sample templates the # endpoints off ${AUTH_DOMAIN}; set AUTH_DOMAIN + override each endpoint with the concrete realm URL. write_env () { local key="$1" val="$2" sed -i "/^\s*#\?\s*${key}=/d" "$ENV_PATH" [ -z "$(tail -c1 "$ENV_PATH" 2>/dev/null)" ] || printf '\n' >> "$ENV_PATH" printf '%s=%s\n' "$key" "$val" >> "$ENV_PATH" } write_env AUTH_DOMAIN "$KC_DOMAIN" write_env OIDC_REALM "$KC_REALM" write_env OIDC_OP_JWKS_ENDPOINT "https://${KC_DOMAIN}/realms/${KC_REALM}/protocol/openid-connect/certs" write_env OIDC_OP_AUTHORIZATION_ENDPOINT "https://${KC_DOMAIN}/realms/${KC_REALM}/protocol/openid-connect/auth" write_env OIDC_OP_TOKEN_ENDPOINT "https://${KC_DOMAIN}/realms/${KC_REALM}/protocol/openid-connect/token" write_env OIDC_OP_USER_ENDPOINT "https://${KC_DOMAIN}/realms/${KC_REALM}/protocol/openid-connect/userinfo" write_env OIDC_OP_LOGOUT_ENDPOINT "https://${KC_DOMAIN}/realms/${KC_REALM}/protocol/openid-connect/logout" write_env OIDC_RP_CLIENT_ID "$KC_CLIENT" write_env OIDC_RP_SIGN_ALGO "RS256" write_env OIDC_RP_SCOPES "openid email" echo " lasuite-meet install_steps: OIDC env wired into .env (deploy will pick it up, no reconverge)"