#!/usr/bin/env bash # T05 acceptance checks for production Forgejo on railiance01 (RAIL-HO-WP-0005). set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BASE_URL="${FORGEJO_BASE_URL:-https://forgejo.coulomb.social}" KUBECONFIG="${KUBECONFIG:-$HOME/.kube/config-hosteurope}" FORGEJO_NAMESPACE="${FORGEJO_NAMESPACE:-forgejo}" FORGEJO_DB_NAMESPACE="${FORGEJO_DB_NAMESPACE:-databases}" FORGEJO_DB_CLUSTER="${FORGEJO_DB_CLUSTER:-forgejo-db}" FORGEJO_OPERATOR_USER="${FORGEJO_OPERATOR_USER:-tegwick}" TOKEN_FILE="${FORGEJO_TOKEN_FILE:-/tmp/forgejo-tegwick-api-token}" export KUBECONFIG pass=0 fail=0 warn=0 ok() { echo " PASS $*"; pass=$((pass + 1)); } bad() { echo " FAIL $*" >&2; fail=$((fail + 1)); } note() { echo " WARN $*"; warn=$((warn + 1)); } echo "Forgejo T05 verify — ${BASE_URL}" echo "kubeconfig: ${KUBECONFIG}" echo # Web + OCI registry smoke if FORGEJO_BASE_URL="${BASE_URL}" "${ROOT}/tools/forgejo-smoke.sh" >/dev/null 2>&1; then ok "web + OCI registry smoke" else bad "web + OCI registry smoke" fi # Kubernetes workload if kubectl get pod -n "${FORGEJO_NAMESPACE}" -l app.kubernetes.io/instance=forgejo \ -o jsonpath='{.items[0].status.phase}' 2>/dev/null | grep -q Running; then ok "forgejo app pod Running" else bad "forgejo app pod not Running" fi if kubectl get deploy forgejo-runner -n "${FORGEJO_NAMESPACE}" >/dev/null 2>&1; then ready="$(kubectl get deploy forgejo-runner -n "${FORGEJO_NAMESPACE}" \ -o jsonpath='{.status.readyReplicas}/{.spec.replicas}' 2>/dev/null || echo 0/0)" if [[ "${ready}" == "1/1" ]]; then ok "forgejo-runner ready (${ready})" else note "forgejo-runner replicas ${ready}" fi else bad "forgejo-runner deployment missing" fi # TLS ingress if kubectl get certificate forgejo-tls -n "${FORGEJO_NAMESPACE}" \ -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null | grep -q True; then ok "TLS certificate Ready" else bad "TLS certificate not Ready" fi # Database if kubectl get cluster "${FORGEJO_DB_CLUSTER}" -n "${FORGEJO_DB_NAMESPACE}" \ -o jsonpath='{.status.phase}' 2>/dev/null | grep -qi healthy; then ok "forgejo-db cluster healthy" else bad "forgejo-db cluster not healthy" fi # Mailer via OpenBao/ESO (not SOPS) if kubectl get externalsecret forgejo-mailer -n "${FORGEJO_NAMESPACE}" \ -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null | grep -q True; then ok "forgejo-mailer ExternalSecret Ready" else bad "forgejo-mailer ExternalSecret not Ready" fi # SOPS secret files (encrypted sentinel — decrypt optional) for f in helm/forgejo-secrets.sops.yaml helm/forgejo-runner-registration.sops.yaml; do if [[ -f "${ROOT}/${f}" ]] && grep -q '^sops:' "${ROOT}/${f}"; then ok "SOPS file present: ${f}" if command -v sops >/dev/null 2>&1 && sops -d "${ROOT}/${f}" >/dev/null 2>&1; then ok "SOPS decrypt: ${f}" else note "SOPS decrypt skipped (no sops or age key): ${f}" fi elif [[ "${f}" == *runner-registration* ]]; then if kubectl get secret forgejo-runner-registration -n "${FORGEJO_NAMESPACE}" >/dev/null 2>&1; then note "runner registration in cluster only — encrypt helm/forgejo-runner-registration.sops.yaml on operator host with age key" else bad "missing runner registration secret" fi else bad "missing SOPS file: ${f}" fi done # Operator SSH (tegwick, not forgejo_admin) if ssh -o BatchMode=yes -o ConnectTimeout=8 forgejo-remote 2>&1 | grep -q "Hi there, ${FORGEJO_OPERATOR_USER}!"; then ok "SSH forgejo-remote authenticates as ${FORGEJO_OPERATOR_USER}" else bad "SSH forgejo-remote does not authenticate as ${FORGEJO_OPERATOR_USER}" fi # Operator API account if [[ -f "${TOKEN_FILE}" ]]; then token="$(cat "${TOKEN_FILE}")" admin="$(curl -fsS -H "Authorization: token ${token}" \ "${BASE_URL}/api/v1/users/${FORGEJO_OPERATOR_USER}" | python3 -c \ "import sys,json; print(json.load(sys.stdin).get('is_admin', False))" 2>/dev/null || echo false)" if [[ "${admin}" == "True" ]]; then ok "operator user ${FORGEJO_OPERATOR_USER} is admin (API)" else bad "operator user ${FORGEJO_OPERATOR_USER} is not admin" fi else note "no API token at ${TOKEN_FILE} — skip operator admin API check" fi # Git HTTPS reachability (no creds — expect 401/200 on repo HEAD) code="$(curl -sS -o /dev/null -w '%{http_code}' "${BASE_URL}/coulomb/glas-harness")" if [[ "${code}" == "200" ]]; then ok "public repo HTTPS (${code})" else bad "public repo HTTPS unexpected (${code})" fi echo echo "Summary: ${pass} pass, ${fail} fail, ${warn} warn" if [[ "${fail}" -gt 0 ]]; then exit 1 fi