#!/usr/bin/env bash # gitea-api.sh — READ-ONLY Gitea API helper. Issues GET requests only. # # Usage: gitea-api.sh [curl-args...] # Example: gitea-api.sh /orgs/sporel/repos # gitea-api.sh repos/calic/claude-config # gitea-api.sh /orgs/sporel/repos?limit=100 | jq '.[].full_name' # # Path may include or omit a leading slash and the "api/v1/" prefix. # Output is the raw JSON body (pretty-printed via jq if available). # # Auth resolution (first that works): # 1. $GITEA_TOKEN env var (use this in dev environments) # 2. temp read-only token via the local `gitea` docker container (auto-cleaned) # 3. unauthenticated (public endpoints only) # # Config: $GITEA_URL (default http://localhost:3100 on the host; # set to https://git.davoryn.de in dev environments) # # This script is SAFE to allowlist: it can only read (GET). It never POSTs, # PUTs, PATCHes or DELETEs application data. The only writes it performs are # creating + immediately deleting its own short-lived read-scope token. # # Self-maintaining: if a request fails, the error + HTTP code are printed; if # that was insufficient to diagnose, improve this script's error handling. set -uo pipefail if [ $# -lt 1 ]; then echo "usage: gitea-api.sh [curl-args...]" >&2 exit 2 fi PATH_ARG="$1"; shift GITEA_URL="${GITEA_URL:-http://localhost:3100}" GITEA_USER="${GITEA_USER:-calic}" # normalise path -> api/v1/ p="${PATH_ARG#/}"; p="${p#api/v1/}" URL="${GITEA_URL%/}/api/v1/${p}" TOKEN="${GITEA_TOKEN:-}" TMP_TOKEN_NAME="" cleanup() { if [ -n "$TMP_TOKEN_NAME" ]; then curl -s -X DELETE -u "${GITEA_USER}:${TOKEN}" \ "${GITEA_URL%/}/api/v1/users/${GITEA_USER}/tokens/${TMP_TOKEN_NAME}" >/dev/null 2>&1 || true fi } trap cleanup EXIT if [ -z "$TOKEN" ] && docker ps --format '{{.Names}}' 2>/dev/null | grep -qx gitea; then TMP_TOKEN_NAME="claude-api-$$" TOKEN=$(docker exec --user git gitea gitea admin user generate-access-token \ -u "$GITEA_USER" -t "$TMP_TOKEN_NAME" \ --scopes read:organization,read:repository,read:user,read:issue,read:misc \ --raw 2>/dev/null) || TOKEN="" [ -z "$TOKEN" ] && TMP_TOKEN_NAME="" fi AUTH=() [ -n "$TOKEN" ] && AUTH=(-H "Authorization: token $TOKEN") BODY_FILE="$(mktemp)"; trap 'rm -f "$BODY_FILE"; cleanup' EXIT CODE=$(curl -s -o "$BODY_FILE" -w "%{http_code}" -X GET "${AUTH[@]}" "$URL") if [ "$CODE" != "200" ]; then echo "ERROR: GET $URL -> HTTP $CODE" >&2 [ -z "$TOKEN" ] && echo "HINT: no token (set GITEA_TOKEN or run where the gitea container is reachable)" >&2 [ "$CODE" = "401" ] && echo "HINT: 401 — token missing/expired/insufficient scope" >&2 [ "$CODE" = "404" ] && echo "HINT: 404 — check the path (e.g. orgs//repos, repos//)" >&2 cat "$BODY_FILE" >&2 exit 1 fi if command -v jq >/dev/null 2>&1; then jq . < "$BODY_FILE"; else cat "$BODY_FILE"; fi