# Gitea Auth Module (Shared) Centralized authentication for Gitea API. **NEVER hardcode credentials in agent code.** ## Auth Resolution Order ``` 1. GITEA_TOKEN env var → Use directly (PREFERRED) 2. GITEA_USER + GITEA_PASS → Create temporary token via Basic Auth 3. .env file → Read env vars from .env 4. Interactive prompt → Ask user (last resort) ``` ## Configuration All credentials come from environment variables defined in `.kilo/gitea.jsonc`: | Env Var | Required | Description | |---------|----------|-------------| | `GITEA_API_URL` | No | API base URL (default: `https://git.softuniq.eu/api/v1`) | | `GITEA_TOKEN` | Preferred | Pre-existing API token | | `GITEA_USER` | Fallback | Username for Basic Auth token creation | | `GITEA_PASS` | Fallback | Password for Basic Auth token creation | | `GITEA_TARGET_REPO` | No | Override target project (auto-detected otherwise) | ## Python Auth Function ```python import os import base64 import json import urllib.request def get_gitea_config(): """Load Gitea configuration from env vars. NEVER hardcode credentials.""" return { 'api_url': os.environ.get('GITEA_API_URL', 'https://git.softuniq.eu/api/v1'), 'token': os.environ.get('GITEA_TOKEN', ''), 'user': os.environ.get('GITEA_USER', ''), 'pass': os.environ.get('GITEA_PASS', ''), } def get_gitea_token(): """Get Gitea API token. Prefers GITEA_TOKEN env var. Falls back to creating token via Basic Auth from GITEA_USER/GITEA_PASS. Raises ValueError if no credentials available.""" config = get_gitea_config() # 1. Use existing token (preferred) if config['token']: return config['token'] # 2. Create token via Basic Auth (fallback) user = config['user'] password = config['pass'] # Note: 'pass' is reserved word, use config['pass'] if not user or not password: raise ValueError( 'Gitea auth required. Set GITEA_TOKEN or GITEA_USER+GITEA_PASS env vars. ' 'Create .env file with: GITEA_TOKEN=your-token' ) credentials = base64.b64encode(f"{user}:{password}".encode()).decode() req = urllib.request.Request( f"{config['api_url']}/users/{user}/tokens", data=json.dumps({"name": f"agent-{os.getpid()}", "scopes": ["all"]}).encode(), headers={ 'Content-Type': 'application/json', 'Authorization': f'Basic {credentials}', }, method='POST', ) with urllib.request.urlopen(req) as r: return json.loads(r.read())['sha1'] ``` ## Bash Auth Function ```bash # Get Gitea token — prefers GITEA_TOKEN, falls back to Basic Auth get_gitea_token() { if [ -n "$GITEA_TOKEN" ]; then echo "$GITEA_TOKEN" return fi if [ -z "$GITEA_USER" ] || [ -z "$GITEA_PASS" ]; then echo "ERROR: Set GITEA_TOKEN or GITEA_USER+GITEA_PASS" >&2 return 1 fi local API_URL="${GITEA_API_URL:-https://git.softuniq.eu/api/v1}" local CRED=$(echo -n "$GITEA_USER:$GITEA_PASS" | base64) curl -s -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Basic $CRED" \ -d '{"name":"agent-token","scopes":["all"]}' \ "$API_URL/users/$GITEA_USER/tokens" | jq -r '.sha1 // empty' } ``` ## .env File Template ```bash # Gitea Integration (NEVER commit this file) GITEA_API_URL=https://git.softuniq.eu/api/v1 GITEA_TOKEN=your-api-token-here # Fallback (only if no token): # GITEA_USER=your-username # GITEA_PASS=your-password # GITEA_TARGET_REPO=Owner/RepoName ``` ## CRITICAL RULES 1. **NEVER hardcode credentials** — no `username = "NW"` or `password = "eshkink0t"` in any file 2. **NEVER commit `.env`** — it's in `.gitignore` 3. **ALWAYS prefer `GITEA_TOKEN`** — tokens are scoped and revocable 4. **Fallback uses env vars** — `GITEA_USER` + `GITEA_PASS`, not hardcoded strings 5. **Raise error if no creds** — don't silently fail, tell user to set env vars 6. **Use this module** — all Gitea API calls should use `get_gitea_token()` from here