AkurAI Build
Menu

AkurAI-Build

public

Latest change 30e6b8c347048d64c2c048dfd05a8ded219d37f6 - Host authenticated Git repositories over Smart HTTP with repo host/sync CLI by Ólafur Búi Ólafsson

#!/usr/bin/env python3
import json
import os
import secrets
import stat
import subprocess
import sys
import tempfile
import urllib.request
from pathlib import Path

if len(sys.argv) != 6:
    raise SystemExit("usage: provision-app-oidc.py NAME REDIRECT_URI ENV_PREFIX ALLOWED_EMAIL PASSVAULT_FOLDER")
name, redirect_uri, prefix, allowed_email, folder_text = sys.argv[1:]
folder_id = int(folder_text)

remote = r'''set -euo pipefail
set -a
. /etc/akurai-idp/idp.env
set +a
python3 - "$1" "$2" <<'PY'
import json, os, sys, urllib.request
base="http://127.0.0.1:3500"
token=os.environ["IDP_ADMIN_TOKEN"]
def call(path, method="GET", body=None):
    data=None if body is None else json.dumps(body).encode()
    req=urllib.request.Request(base+path, data=data, method=method, headers={"Authorization":"Bearer "+token,"Content-Type":"application/json"})
    with urllib.request.urlopen(req) as response: return json.load(response)
tenants=call("/admin/tenants")
if isinstance(tenants, dict): tenants=tenants.get("data", tenants.get("tenants", []))
if not tenants: raise SystemExit("no IDP tenant available")
tenant=next((t for t in tenants if t.get("domain")=="olibuijr.com"), tenants[0])
client=call("/admin/clients", "POST", {"name":sys.argv[1],"tenant_id":tenant["id"],"redirect_uris":[sys.argv[2]],"grant_types":["authorization_code","refresh_token"],"scopes":["openid","profile","email","groups"],"first_party":True})
print(json.dumps(client, separators=(",",":")))
PY
'''
created = subprocess.run(
    ["ssh", "akurai-ec2", "sudo", "bash", "-s", "--", name, redirect_uri],
    input=remote,
    text=True,
    capture_output=True,
)
if created.returncode:
    raise SystemExit(created.stderr.strip().splitlines()[-1] if created.stderr.strip() else "remote OIDC provisioning failed")
client = json.loads(created.stdout)
client_id = client.get("id") or client.get("client_id")
client_secret = client["client_secret"]

vault_env = Path.home() / ".config/omp/akurai-passvault-mcp.env"
if stat.S_IMODE(vault_env.stat().st_mode) != 0o600:
    raise SystemExit("PassVault environment must be mode 0600")
values = {}
for line in vault_env.read_text().splitlines():
    if line and not line.startswith("#") and "=" in line:
        key, value = line.split("=", 1)
        values[key] = value.strip().strip("'\"")
vault_token = values["AKURAI_PASSVAULT_MCP_TOKEN"]

def vault_entry(entry_name, username, password, notes):
    payload = {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_entry","arguments":{"name":entry_name,"username":username,"password":password,"uri":"https://auth.olibuijr.com","notes":notes,"folderId":folder_id}}}
    request = urllib.request.Request("https://akurai-passvault.olibuijr.com/mcp", data=json.dumps(payload).encode(), headers={"Authorization":"Bearer "+vault_token,"Content-Type":"application/json"})
    with urllib.request.urlopen(request) as response:
        result = json.load(response)
    if "error" in result:
        raise RuntimeError("PassVault rejected credential storage")

mcp_token = secrets.token_urlsafe(48)
vault_entry(f"{name} OIDC client", client_id, client_secret, f"Managed OIDC client; callback {redirect_uri}")
vault_entry(f"{name} MCP token", "omp-mcp", mcp_token, "Bearer token for the AkurAI Tasks MCP endpoint")

env_lines = [
    f"{prefix}_IDP_ISSUER=https://auth.olibuijr.com",
    f"{prefix}_IDP_INTERNAL_URL=http://127.0.0.1:3500",
    f"{prefix}_IDP_CLIENT_ID={client_id}",
    f"{prefix}_IDP_CLIENT_SECRET={client_secret}",
    f"{prefix}_IDP_REDIRECT={redirect_uri}",
    f"{prefix}_IDP_ALLOW={allowed_email}",
    f"{prefix}_ALLOWED_ORIGIN=https://akurai-tasks.olibuijr.com",
    f"{prefix}_MCP_TOKEN={mcp_token}",
]
with tempfile.NamedTemporaryFile("w", delete=False) as handle:
    handle.write("\n".join(env_lines)+"\n")
    local_env = handle.name
os.chmod(local_env, 0o600)
try:
    subprocess.run([str(Path.home()/".local/bin/akurai-ec2"), "ship", local_env, "/tmp/akurai-tasks.env"], check=True, stdout=subprocess.DEVNULL)
    subprocess.run([str(Path.home()/".local/bin/akurai-ec2"), "ssh", "sudo install -d -m 0750 -o root -g ubuntu /etc/akurai-tasks && sudo install -m 0640 -o root -g ubuntu /tmp/akurai-tasks.env /etc/akurai-tasks/akurai-tasks.env && rm -f /tmp/akurai-tasks.env"], check=True, stdout=subprocess.DEVNULL)
finally:
    os.unlink(local_env)
print("OIDC client, PassVault references, and protected service environment provisioned.")