- Remove all hardcoded NW:eshkink0t credentials from 9 files across skills, commands, rules, and specs - Add .kilo/shared/gitea-auth.md with get_gitea_token() and .kilo/gitea.jsonc config structure - All Gitea API callers now use env vars (GITEA_TOKEN → GITEA_USER+GITEA_PASS → ValueError) - Fix task-analysis/SKILL.md broken functions (orphaned req references, stray parentheses) - Replace hardcoded UniqueSoft/APAW API URLs with get_target_repo() auto-detection in 3 files - Update README.md, STRUCTURE.md, AGENTS.md with centralized auth documentation - Add EVOLUTION_LOG Entry #5 documenting credentials extrication
124 lines
4.0 KiB
Markdown
124 lines
4.0 KiB
Markdown
# 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 |