"""Authentik-shell payload for an idempotent MCP service account and app password. Run by piping this file to ``ak shell`` with MCP_USERNAME, MCP_DISPLAY_NAME, MCP_TOKEN_IDENTIFIER and MCP_SECRET_FILE set inside the container. The secret is read from a temporary file and is never printed. """ from __future__ import annotations import json import os from pathlib import Path from authentik.core.models import Token, TokenIntents, User, UserTypes from django.db import transaction def required(name: str) -> str: value = os.environ.get(name, "").strip() if not value: raise ValueError(f"missing {name}") return value username = required("MCP_USERNAME") display_name = required("MCP_DISPLAY_NAME") identifier = required("MCP_TOKEN_IDENTIFIER") secret_path = Path(required("MCP_SECRET_FILE")) if secret_path.is_symlink() or not secret_path.is_file() or secret_path.stat().st_size > 8192: raise ValueError("invalid app-password secret file") secret = secret_path.read_text(encoding="utf-8").strip() if not secret or "\n" in secret or "\r" in secret: raise ValueError("app-password secret must contain one non-empty line") with transaction.atomic(): user, created = User.objects.get_or_create( username=username, defaults={ "name": display_name, "path": "users", "type": UserTypes.SERVICE_ACCOUNT, }, ) if not created and user.type not in { UserTypes.SERVICE_ACCOUNT, UserTypes.INTERNAL_SERVICE_ACCOUNT, }: raise ValueError("existing Authentik identity is not a service account") if user.name != display_name: user.name = display_name user.save(update_fields=["name"]) token, token_created = Token.objects.get_or_create( identifier=identifier, defaults={ "user": user, "intent": TokenIntents.INTENT_APP_PASSWORD, "key": secret, "expiring": False, "description": "ITWorx MCP Hub Codex machine credential", }, ) if not token_created: if token.user_id != user.pk or token.intent != TokenIntents.INTENT_APP_PASSWORD: raise ValueError("existing Authentik token identifier has incompatible ownership") if os.environ.get("MCP_ROTATE", "false").lower() == "true": token.key = secret token.expiring = False token.save(update_fields=["key", "expiring"]) print( json.dumps( { "created": created, "tokenCreated": token_created, "subject": str(user.uuid), "username": user.username, "tokenIdentifier": token.identifier, }, sort_keys=True, ) ) del secret