Initial: gitea-api (read-only) + sporel-commit tools with Claude skills
This commit is contained in:
76
gitea-api.sh
Executable file
76
gitea-api.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# gitea-api.sh — READ-ONLY Gitea API helper. Issues GET requests only.
|
||||
#
|
||||
# Usage: gitea-api.sh <path> [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 <path> [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/<path>
|
||||
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/<org>/repos, repos/<owner>/<name>)" >&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
|
||||
Reference in New Issue
Block a user