#!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Usage: Scripts/forgejo-dispatch-via-host.sh [--ref ] [--inputs ] [--inputs-file ] [--return-run-info] Dispatch a Burrow Forgejo workflow by SSHing to the live forge host and using the managed dispatcher token from the host runtime. Environment: FORGEJO_BASE_URL Default: https://git.burrow.net FORGEJO_REPO Default: hackclub/burrow BURROW_FORGE_HOST Default: root@git.burrow.net BURROW_FORGE_HOST_ADDRESS Optional SSH HostName override BURROW_FORGE_SSH_KEY Optional explicit SSH private key AGE_FORGE_SSH_KEY Optional injected SSH private key material BURROW_FORGE_DISPATCHER_CONFIG_FILE Default: /run/agenix/burrowForgejoNscDispatcherConfig EOF } base_url="${FORGEJO_BASE_URL:-https://git.burrow.net}" repo_slug="${FORGEJO_REPO:-hackclub/burrow}" forge_host="${BURROW_FORGE_HOST:-root@git.burrow.net}" forge_host_address="${BURROW_FORGE_HOST_ADDRESS:-}" dispatcher_config_file="${BURROW_FORGE_DISPATCHER_CONFIG_FILE:-/run/agenix/burrowForgejoNscDispatcherConfig}" workflow="" ref="main" inputs_json="" return_run_info="false" while [[ $# -gt 0 ]]; do case "$1" in -h|--help) usage exit 0 ;; --ref) ref="${2:-}" shift 2 ;; --inputs) inputs_json="${2:-}" shift 2 ;; --inputs-file) inputs_json="$(cat "${2:-}")" shift 2 ;; --return-run-info) return_run_info="true" shift ;; *) if [[ -z "$workflow" ]]; then workflow="$1" shift else echo "Unexpected argument: $1" >&2 usage >&2 exit 64 fi ;; esac done if [[ -z "$workflow" ]]; then echo "Missing workflow name or file, for example build-release.yml." >&2 usage >&2 exit 64 fi script_dir="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" resolved_forge_ssh_key="$("${script_dir}/resolve-forge-ssh-key.sh")" eval "$resolved_forge_ssh_key" ssh_key="${BURROW_FORGE_SSH_KEY}" if [[ -n "$inputs_json" ]]; then if ! python3 - "$inputs_json" <<'PY' >/dev/null import json import sys value = json.loads(sys.argv[1]) if not isinstance(value, dict): raise SystemExit(1) PY then echo "--inputs must be a JSON object." >&2 exit 64 fi fi workflow_path="$(python3 - "$workflow" <<'PY' import sys import urllib.parse print(urllib.parse.quote(sys.argv[1], safe="")) PY )" payload="$(python3 - "$ref" "$inputs_json" "$return_run_info" <<'PY' import json import sys ref = sys.argv[1] inputs_arg = sys.argv[2] return_run_info = sys.argv[3] == "true" payload = {"ref": ref} if inputs_arg: inputs = json.loads(inputs_arg) payload["inputs"] = {key: str(value) for key, value in inputs.items()} if return_run_info: payload["return_run_info"] = True print(json.dumps(payload)) PY )" payload_b64="$(python3 - "$payload" <<'PY' import base64 import sys print(base64.b64encode(sys.argv[1].encode()).decode()) PY )" ssh_opts=( -i "$ssh_key" -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o GlobalKnownHostsFile=/dev/null -o StrictHostKeyChecking=accept-new ) if [[ -n "$forge_host_address" ]]; then ssh_opts+=(-o "HostName=$forge_host_address") fi response="$( ssh "${ssh_opts[@]}" "$forge_host" bash -s -- \ "$base_url" "$repo_slug" "$workflow_path" "$dispatcher_config_file" "$payload_b64" <<'EOF' set -euo pipefail base_url="$1" repo_slug="$2" workflow_path="$3" dispatcher_config_file="$4" payload_b64="$5" payload="$(python3 - "$payload_b64" <<'PY' import base64 import sys print(base64.b64decode(sys.argv[1]).decode()) PY )" if [[ ! -s "$dispatcher_config_file" ]]; then echo "Forge dispatcher config is missing or empty: $dispatcher_config_file" >&2 exit 1 fi runtime_token="$( awk ' /^[A-Za-z0-9_-]+:/ { in_forgejo = ($0 ~ /^forgejo:/); next } in_forgejo && /^[[:space:]]+token:/ { sub(/^[[:space:]]+token:[[:space:]]*/, "") gsub(/^"/, "") gsub(/"$/, "") gsub(/^\047/, "") gsub(/\047$/, "") print exit } ' "$dispatcher_config_file" | tr -d "\r\n" )" if [[ -z "$runtime_token" ]]; then echo "Forge dispatcher token not found in $dispatcher_config_file" >&2 exit 1 fi url="${base_url%/}/api/v1/repos/${repo_slug}/actions/workflows/${workflow_path}/dispatches" response_file="$(mktemp)" http_code="$( curl -sS -o "$response_file" -w '%{http_code}' -X POST \ -H "Authorization: token ${runtime_token}" \ -H "Content-Type: application/json" \ --data-binary "$payload" \ "$url" )" if [[ "$http_code" != 2* ]]; then cat "$response_file" >&2 rm -f "$response_file" exit 22 fi cat "$response_file" rm -f "$response_file" EOF )" if [[ "$return_run_info" == "true" ]]; then printf '%s\n' "$response" else echo "Dispatched ${workflow} on ${ref} via ${forge_host}." fi