Add Forgejo T05 verify, operator bootstrap, and security hardening
Introduce forgejo-verify acceptance checks, idempotent operator bootstrap, runner registration SOPS capture helper, and session/security Helm values.
This commit is contained in:
parent
9b31f229e8
commit
3a9236148a
8 changed files with 436 additions and 1 deletions
104
tools/forgejo-operator-bootstrap.sh
Executable file
104
tools/forgejo-operator-bootstrap.sh
Executable file
|
|
@ -0,0 +1,104 @@
|
|||
#!/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}!"
|
||||
Loading…
Add table
Add a link
Reference in a new issue