104 lines
3.7 KiB
Bash
104 lines
3.7 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
# Idempotent operator account bootstrap for Forgejo (RAIL-HO-WP-0005 T05).
|
||
|
|
# Does not commit secrets — uses API token from file or env.
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
FORGEJO_API="${FORGEJO_API:-https://forgejo.coulomb.social/api/v1}"
|
||
|
|
FORGEJO_ORG="${FORGEJO_ORG:-coulomb}"
|
||
|
|
FORGEJO_OPERATOR_USER="${FORGEJO_OPERATOR_USER:-tegwick}"
|
||
|
|
FORGEJO_OPERATOR_EMAIL="${FORGEJO_OPERATOR_EMAIL:-bernd.worsch@gmail.com}"
|
||
|
|
FORGEJO_OPERATOR_SSH_KEY="${FORGEJO_OPERATOR_SSH_KEY:-$HOME/.ssh/id_gitea.pub}"
|
||
|
|
FORGEJO_OPERATOR_SSH_TITLE="${FORGEJO_OPERATOR_SSH_TITLE:-workstation-automation}"
|
||
|
|
TOKEN_FILE="${FORGEJO_TOKEN_FILE:-/tmp/forgejo-tegwick-api-token}"
|
||
|
|
|
||
|
|
if [[ -n "${FORGEJO_ADMIN_TOKEN:-}" ]]; then
|
||
|
|
TOKEN="${FORGEJO_ADMIN_TOKEN}"
|
||
|
|
elif [[ -f "${TOKEN_FILE}" ]]; then
|
||
|
|
TOKEN="$(cat "${TOKEN_FILE}")"
|
||
|
|
else
|
||
|
|
echo "Set FORGEJO_ADMIN_TOKEN or create ${TOKEN_FILE}" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
AUTH=(-H "Authorization: token ${TOKEN}")
|
||
|
|
|
||
|
|
user_status() {
|
||
|
|
curl -sS -o /dev/null -w '%{http_code}' "${AUTH[@]}" "${FORGEJO_API}/users/${FORGEJO_OPERATOR_USER}"
|
||
|
|
}
|
||
|
|
|
||
|
|
echo "==> Forgejo operator bootstrap: ${FORGEJO_OPERATOR_USER}"
|
||
|
|
|
||
|
|
case "$(user_status)" in
|
||
|
|
200)
|
||
|
|
echo " user exists"
|
||
|
|
;;
|
||
|
|
404)
|
||
|
|
echo " creating user ${FORGEJO_OPERATOR_USER}"
|
||
|
|
FORGEJO_OPERATOR_USER="${FORGEJO_OPERATOR_USER}" \
|
||
|
|
FORGEJO_OPERATOR_EMAIL="${FORGEJO_OPERATOR_EMAIL}" \
|
||
|
|
curl -fsS -X POST "${FORGEJO_API}/admin/users" "${AUTH[@]}" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d "$(python3 -c "
|
||
|
|
import json, os
|
||
|
|
print(json.dumps({
|
||
|
|
'username': os.environ['FORGEJO_OPERATOR_USER'],
|
||
|
|
'email': os.environ['FORGEJO_OPERATOR_EMAIL'],
|
||
|
|
'password': os.urandom(18).hex(),
|
||
|
|
'must_change_password': False,
|
||
|
|
'send_notify': False,
|
||
|
|
}))
|
||
|
|
")" >/dev/null
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
echo "Unexpected user lookup status for ${FORGEJO_OPERATOR_USER}" >&2
|
||
|
|
exit 1
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
|
||
|
|
# Promote to site admin
|
||
|
|
curl -fsS -X PATCH "${FORGEJO_API}/admin/users/${FORGEJO_OPERATOR_USER}" "${AUTH[@]}" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{"admin":true,"prohibit_login":false}' >/dev/null
|
||
|
|
echo " admin=true"
|
||
|
|
|
||
|
|
# Org Owners team membership
|
||
|
|
team_id="$(curl -fsS "${AUTH[@]}" "${FORGEJO_API}/orgs/${FORGEJO_ORG}/teams" \
|
||
|
|
| python3 -c "import sys,json; teams=json.load(sys.stdin); print(next((t['id'] for t in teams if t.get('name')=='Owners'), ''))")"
|
||
|
|
if [[ -n "${team_id}" ]]; then
|
||
|
|
curl -fsS -X PUT "${AUTH[@]}" \
|
||
|
|
"${FORGEJO_API}/teams/${team_id}/members/${FORGEJO_OPERATOR_USER}" >/dev/null 2>&1 \
|
||
|
|
&& echo " org ${FORGEJO_ORG} Owners team" \
|
||
|
|
|| echo " (already in Owners team or API skipped)"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# SSH key for git+ssh
|
||
|
|
if [[ ! -f "${FORGEJO_OPERATOR_SSH_KEY}" ]]; then
|
||
|
|
echo "Missing SSH public key: ${FORGEJO_OPERATOR_SSH_KEY}" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
existing="$(curl -fsS "${AUTH[@]}" "${FORGEJO_API}/users/${FORGEJO_OPERATOR_USER}/keys" \
|
||
|
|
| FORGEJO_OPERATOR_SSH_KEY="${FORGEJO_OPERATOR_SSH_KEY}" python3 -c "
|
||
|
|
import json, os, sys
|
||
|
|
want = open(os.environ['FORGEJO_OPERATOR_SSH_KEY']).read().strip()
|
||
|
|
keys = json.load(sys.stdin)
|
||
|
|
print(any((k.get('key') or '').strip() == want for k in keys))
|
||
|
|
")"
|
||
|
|
if [[ "${existing}" == "True" ]]; then
|
||
|
|
echo " SSH key already present"
|
||
|
|
else
|
||
|
|
FORGEJO_OPERATOR_SSH_TITLE="${FORGEJO_OPERATOR_SSH_TITLE}" \
|
||
|
|
FORGEJO_OPERATOR_SSH_KEY="${FORGEJO_OPERATOR_SSH_KEY}" \
|
||
|
|
curl -fsS -X POST "${FORGEJO_API}/admin/users/${FORGEJO_OPERATOR_USER}/keys" "${AUTH[@]}" \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d "$(python3 -c "
|
||
|
|
import json, os
|
||
|
|
print(json.dumps({
|
||
|
|
'title': os.environ['FORGEJO_OPERATOR_SSH_TITLE'],
|
||
|
|
'key': open(os.environ['FORGEJO_OPERATOR_SSH_KEY']).read().strip(),
|
||
|
|
}))
|
||
|
|
")" >/dev/null
|
||
|
|
echo " SSH key added (${FORGEJO_OPERATOR_SSH_TITLE})"
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo "==> Operator bootstrap complete: ${FORGEJO_OPERATOR_USER}"
|
||
|
|
echo " Test: ssh forgejo-remote # expect Hi there, ${FORGEJO_OPERATOR_USER}!"
|