# services/comms/mas-local-users-ensure-job.yaml apiVersion: batch/v1 kind: Job metadata: name: mas-local-users-ensure-5 namespace: comms spec: backoffLimit: 1 ttlSecondsAfterFinished: 3600 template: spec: restartPolicy: Never volumes: - name: mas-admin-client secret: secretName: mas-admin-client-runtime items: - key: client_secret path: client_secret containers: - name: ensure image: python:3.11-slim volumeMounts: - name: mas-admin-client mountPath: /etc/mas-admin-client readOnly: true env: - name: MAS_ADMIN_CLIENT_ID value: 01KDXMVQBQ5JNY6SEJPZW6Z8BM - name: MAS_ADMIN_CLIENT_SECRET_FILE value: /etc/mas-admin-client/client_secret - name: MAS_TOKEN_URL value: http://matrix-authentication-service:8080/oauth2/token - name: MAS_ADMIN_API_BASE value: http://matrix-authentication-service:8081/api/admin/v1 - name: SEEDER_USER value: othrys-seeder - name: SEEDER_PASS valueFrom: secretKeyRef: name: atlasbot-credentials-runtime key: seeder-password - name: BOT_USER value: atlasbot - name: BOT_PASS valueFrom: secretKeyRef: name: atlasbot-credentials-runtime key: bot-password command: - /bin/sh - -c - | set -euo pipefail pip install --no-cache-dir requests >/dev/null python - <<'PY' import base64 import os import time import requests import urllib.parse MAS_ADMIN_CLIENT_ID = os.environ["MAS_ADMIN_CLIENT_ID"] MAS_ADMIN_CLIENT_SECRET_FILE = os.environ["MAS_ADMIN_CLIENT_SECRET_FILE"] MAS_TOKEN_URL = os.environ["MAS_TOKEN_URL"] MAS_ADMIN_API_BASE = os.environ["MAS_ADMIN_API_BASE"].rstrip("/") AUTH_BASE = "http://matrix-authentication-service:8080" SERVER_NAME = "live.bstein.dev" def admin_token(): with open(MAS_ADMIN_CLIENT_SECRET_FILE, "r", encoding="utf-8") as f: secret = f.read().strip() basic = base64.b64encode(f"{MAS_ADMIN_CLIENT_ID}:{secret}".encode()).decode() last = None for attempt in range(1, 6): try: r = requests.post( MAS_TOKEN_URL, headers={"Authorization": f"Basic {basic}"}, data={"grant_type": "client_credentials", "scope": "urn:mas:admin"}, timeout=30, ) if r.status_code == 200: return r.json()["access_token"] except Exception as exc: # noqa: BLE001 last = exc time.sleep(attempt * 2) raise RuntimeError(f"MAS admin token request failed: {last}") def get_user(token, username): r = requests.get( f"{MAS_ADMIN_API_BASE}/users/by-username/{urllib.parse.quote(username)}", headers={"Authorization": f"Bearer {token}"}, timeout=30, ) if r.status_code == 404: return None r.raise_for_status() return r.json()["data"] def create_user(token, username, password): payloads = [ { "data": { "type": "user", "attributes": { "username": username, "password": password, }, } }, {"username": username, "password": password}, ] for payload in payloads: r = requests.post( f"{MAS_ADMIN_API_BASE}/users", headers={"Authorization": f"Bearer {token}"}, json=payload, timeout=30, ) if r.status_code in (200, 201): return r.json().get("data") or {} if r.status_code == 409: return None return None def update_password(token, user_id, password): r = requests.post( f"{MAS_ADMIN_API_BASE}/users/{urllib.parse.quote(user_id)}/set-password", headers={"Authorization": f"Bearer {token}"}, json={"password": password}, timeout=30, ) return r.status_code in (200, 204) def ensure_user(token, username, password): user = get_user(token, username) if user is None: user = create_user(token, username, password) user = get_user(token, username) if user is None: raise RuntimeError(f"failed to ensure user {username}") update_password(token, user["id"], password) login_name = username if not login_name.startswith("@"): login_name = f"@{login_name}:{SERVER_NAME}" r = requests.post( f"{AUTH_BASE}/_matrix/client/v3/login", json={ "type": "m.login.password", "identifier": {"type": "m.id.user", "user": login_name}, "password": password, }, timeout=30, ) if r.status_code != 200: raise RuntimeError(f"login failed for {username}: {r.status_code} {r.text}") token = admin_token() ensure_user(token, os.environ["SEEDER_USER"], os.environ["SEEDER_PASS"]) ensure_user(token, os.environ["BOT_USER"], os.environ["BOT_PASS"]) PY