15 KiB
Gitea — skill de PRs + Actions de gitea.nucleoriofrio.com
Qué es esto
Skill para interactuar con la instancia self-hosted de Gitea del beneficio
Rio Frio (gitea.nucleoriofrio.com, Gitea 1.24.7) hostea el org NucleOS.
Resuelve dos casos de uso principales:
- Crear/leer PRs sin escribir curl ad-hoc cada vez (con guards anti-AI attribution y body UTF-8 safe).
- Killer feature: introspección de runs de Gitea Actions post-merge —
actions-list-runs,actions-view,actions-logs. Cierra el loop GitOps: yo mergeo un PR, el workflowdeploy-infra.ymldispara, y con la skill verifico que deployó OK sin necesitar SSH a nucleo001.
Las operaciones admin (Actions secrets/variables) están bloqueadas porque
el PAT de claudecode0 no es admin del org. Hay un override GITEA_USER_PAT
para esos casos one-shot.
- Server:
https://gitea.nucleoriofrio.com - Auth:
Authorization: token <PAT>(PAT declaudecode0en.env, extraído de la skillbitwardenporsetup.sh) - Override admin:
GITEA_USER_PAT=...en el entorno (one-shot temporal)
Cómo invocarla correctamente
Antes de cualquier query:
-
Verificá
~/.claude/skills/gitea/.env. Si no existe o está vacío:bash ~/.claude/skills/gitea/scripts/setup.shEso extrae el PAT desde la skill
bitwarden(item con substring "Gitea PAT claude-agent-gitops") y lo escribe al.env. Re-corrésetup.shcada vez que rotás el PAT. -
Si una query devuelve 401: el PAT está revocado o el item correcto en bitwarden cambió. Re-corré
setup.sh. Si persiste, podría ser quesetup.shestá agarrando el PAT duplicado equivocado (hay dos items con el mismo nombre en bitwarden, ver "Errores típicos").
Scripts disponibles
| Script | Propósito |
|---|---|
setup.sh |
Extrae PAT de bitwarden, escribe .env, valida con /version |
query.sh |
Helper REST genérico con admin-guard (foundation de todos los demás) |
pr-list.sh |
Lista PRs (con --state open|closed|all, --limit N) |
pr-view.sh |
Ver detalle de un PR (incluye body completo) |
pr-comments.sh |
Lista comentarios de un PR (requiere PAT con read:issue) |
pr-create.sh |
Crear PR con guards anti-AI-attribution + body UTF-8 safe |
repo-create.sh |
Crear repo (default owner = bot user; regla dura: bot user → siempre público) |
actions-list-runs.sh |
Lista runs (filtros client-side: workflow, branch, status, event) |
actions-view.sh |
Detalle de un run + probe del job_id |
actions-logs.sh |
Lee logs con filtros precisos (--tail/--head/--lines/--grep/--errors) |
Ver endpoints.md para los endpoints crudos de la API.
Modelo de seguridad
Admin guard en query.sh
query.sh bloquea cualquier path que matchee:
/admin/*(operaciones admin del server)/orgs/{org}/actions/(secrets|variables)/*/repos/{o}/{r}/actions/(secrets|variables)/*
Mensaje del guard: pide al usuario un PAT temporal con scope admin, lo exporta
como GITEA_USER_PAT=..., y le recuerda BORRAR el PAT desde
https://gitea.nucleoriofrio.com/user/settings/applications apenas termine
(Gitea no tiene PATs efímeros nativos).
# Bypass legítimo del guard:
export GITEA_USER_PAT=<el-pat-temporal-admin>
bash ~/.claude/skills/gitea/scripts/query.sh /repos/NucleOS/X/actions/secrets
unset GITEA_USER_PAT # limpiar al terminar
Anti-AI-attribution guard en pr-create.sh
Regla dura (ver memoria feedback_no_ai_attribution.md). Antes de POST,
escanea title + body por (case-insensitive):
Co-Authored-By: Claude(oAnthropic)🤖Generated with [Claude Code]/Generated with Claude/Generated with AnthropicCreated with Claude/Powered by Claude/Made with Claude
Si match → exit 4 con mensaje + las líneas ofensivas. Esto es imposibilitar, no advertir — el usuario considera deshonesto darle crédito a Claude/Anthropic por trabajo del usuario.
Visibilidad de repos del bot (regla dura)
repo-create.sh rechaza --private cuando el owner es el bot user
(case-insensitive match contra $GITEA_BOT_USER). Justificación: la cuenta
claudeCode0 es del bot, pero el usuario humano tiene que poder auditarla
sin login. Si los repos del bot fueran privados, sería una caja negra. Para
algo realmente privado, crearlo bajo la org NucleOS.
Para repos en orgs (NucleOS u otra), el flag --public o --private es
requerido — sin default sorpresa. Forzá la decisión consciente.
Scope del PAT de claudecode0
El PAT cacheado tiene scope: write:organization, write:package,
write:repository, write:user. NO incluye read:issue / write:issue,
así que pr-comments.sh (que lee issue comments) puede devolver 403. Si el
usuario quiere usar pr-comments o crear PRs con descripciones largas que
generen comentarios, debe regenerar el PAT con esos scopes adicionales y
re-correr setup.sh.
Cuándo usar qué endpoint
Caso típico: "mergeé el PR, ¿deployó OK?"
Después de mergear un PR a main en nucleo-infra, el workflow corre. Para
verificar:
# 1. Ver el último run del workflow:
bash ~/.claude/skills/gitea/scripts/actions-list-runs.sh NucleOS/nucleo-infra --limit 3
# 2. Si está in_progress, esperar 30-60s y reintentar.
# Si terminó, ver los logs:
bash ~/.claude/skills/gitea/scripts/actions-logs.sh NucleOS/nucleo-infra <run_number>
# 3. Si falló, buscar errores específicos:
bash ~/.claude/skills/gitea/scripts/actions-logs.sh NucleOS/nucleo-infra <run> --errors -C 3
"Quiero crear un PR"
Para body con tildes/ñ, siempre pasarlo via --body-file. NO usar heredoc
inline (memoria feedback_api_utf8_encoding.md):
# Crear el body en un archivo (con Write tool, UTF-8 nativo):
cat > /c/Users/jodar/AppData/Local/Temp/pr-body.md <<'EOF'
## Qué cambia
Esto arregla el bug X — resumen de cambios.
## Por qué
[...]
EOF
bash ~/.claude/skills/gitea/scripts/pr-create.sh NucleOS/nucleo-infra \
--head fix/foo \
--title "fix(x): short imperative" \
--body-file /c/Users/jodar/AppData/Local/Temp/pr-body.md
Para body simple sin caracteres especiales, --body "..." inline también va.
"Listame PRs abiertos"
bash ~/.claude/skills/gitea/scripts/pr-list.sh NucleOS/nucleo-infra
# Default state=open, limit=20.
"Ver detalle del PR #14"
bash ~/.claude/skills/gitea/scripts/pr-view.sh NucleOS/nucleo-infra 14
"Mostrame solo los runs que fallaron"
bash ~/.claude/skills/gitea/scripts/actions-list-runs.sh NucleOS/nucleo-infra \
--status failure --limit 20
"Buscá errores en el run 7"
bash ~/.claude/skills/gitea/scripts/actions-logs.sh NucleOS/nucleo-infra 7 --errors -C 3
# --errors es shortcut para --grep '(error|fail|fatal|exception|panic|...)'
"Quiero el log entero del run X para grep-ear con mis tools"
bash ~/.claude/skills/gitea/scripts/actions-logs.sh NucleOS/nucleo-infra X \
--save /c/Users/jodar/AppData/Local/Temp/run-X.log
# Guarda raw (sin sanitizar) para preservar fidelidad.
"Creá un repo nuevo en mi (bot) usuario"
Default owner = $GITEA_BOT_USER (claudeCode0). Siempre público por
regla dura — --private está bloqueado bajo el bot user (exit 5):
bash ~/.claude/skills/gitea/scripts/repo-create.sh skill-foo \
--description "Skill X — qué hace" --license "MIT" --gitignore "Node"
# → claudeCode0/skill-foo (public), html_url + clone_url + ssh_url
"Creá un repo en NucleOS"
Para org, --public o --private es requerido (exit 6 si no pasás
ninguno — sin default sorpresa):
bash ~/.claude/skills/gitea/scripts/repo-create.sh nuevo-servicio \
--owner NucleOS --private --description "..." --gitignore "Go"
Reglas de comportamiento
Filtros sobre logs son obligatorios
Los runs de deploy-infra tienen ~1700 líneas (post-sanitización). Volcar
entero satura mi ventana. Default es siempre summary (header + tail 5/40
según status). Solo usar --full cuando es chico, y nunca sin --i-mean-it
si supera 1000 líneas.
Workflow GitOps (memoria feedback_swarm_changes_via_gitea.md)
Toda modificación al Swarm va por PR + workflow. Después de mergear, antes
de declarar el cambio listo, verificar con actions-logs que el deploy
terminó OK. Sino, esa "termina" es prematura.
Operaciones disruptivas requieren OK explícito
pr-merge no está en la skill (out of scope). Mergear con la API requiere
construir el endpoint manualmente con query.sh y antes pedir confirmación
explícita al usuario — un merge dispara deploy a producción. Memoria
feedback_disruptive_actions.md aplica.
PAT duplicado en bitwarden
Hay 2 items con substring Gitea PAT claude-agent-gitops en el vault de
claudecode0. setup.sh toma el primero. Si la validación falla:
- Listar los items:
bash ~/.claude/skills/bitwarden/scripts/query.sh "/list/object/items?search=Gitea" - Pedirle al usuario que limpie el duplicado desde
https://vault.nucleoriofrio.com(la skillbitwardentiene DELETE bloqueado).
Errores típicos
| Error | Causa | Qué hacer |
|---|---|---|
setup.sh "no encontré ningún item..." |
El PAT no está guardado en bitwarden | Generar PAT en Gitea + guardarlo en bitwarden con substring "Gitea PAT claude-agent-gitops" |
| Validación 401 | PAT revocado o duplicado equivocado | Limpiar duplicados desde web vault, regenerar si es necesario, re-correr setup.sh |
query.sh admin guard exit 3 |
Endpoint requiere admin | Pedir PAT temporal admin al usuario, exportar GITEA_USER_PAT, recordar borrarlo apenas termine |
pr-create.sh exit 4 |
Body con AI attribution | Remover los markers (regla dura) |
pr-comments.sh 403 |
PAT sin scope read:issue |
Regenerar PAT con read:issue+write:issue, re-correr setup.sh |
actions-logs.sh "no pude resolver job_id" |
Probe de ±10 falló (Gitea no expone listado de jobs) | Probar con --job <jid> directo; rangear con query.sh /repos/.../actions/jobs/<jid>/logs manualmente |
actions-list-runs 0 results con filtro |
Filtros son client-side; el server solo respeta limit |
Subir --limit (default 10) para incluir runs más viejos |
Lifecycle: cuándo correr cada script
| Script | Cuándo |
|---|---|
setup.sh |
(a) Primera vez. (b) Cuando el PAT rota. (c) Cuando agregás scopes nuevos al PAT. (d) Cuando 401 inesperado |
query.sh |
Endpoint nuevo o ad-hoc no cubierto por otros scripts |
pr-*.sh |
Operaciones de PRs |
actions-*.sh |
Verificar deploys, debug runs, etc. |
Setup inicial (lo hace el usuario UNA vez)
1. Generar PAT en Gitea
https://gitea.nucleoriofrio.com/user/settings/applications(logueado comoclaudecode0)- "Generate New Token" con scopes:
read:repo,write:repo— push, leer/crear PRs, branchesread:issue,write:issue— comentarios y descripciones de PRsread:user— sanity check de auth- (NO usar admin scopes acá; eso queda para PATs temporales)
- Copiar el token (sólo se ve una vez).
2. Guardar en bitwarden (vault de claudecode0)
- Web:
https://vault.nucleoriofrio.com→ login comoclaudecode0 - New item: name =
claudecode0 · Gitea PAT claude-agent-gitops(cualquier nombre con substringGitea PAT claude-agent-gitopssirve) - Username:
claudecode0. Password: el PAT. - Save.
3. Correr setup
bash ~/.claude/skills/gitea/scripts/setup.sh
Esperado:
→ Listo: Gitea 1.24.7 | user=claudeCode0 | https://gitea.nucleoriofrio.com
4. Probar
bash ~/.claude/skills/gitea/scripts/pr-list.sh NucleOS/nucleo-infra
bash ~/.claude/skills/gitea/scripts/actions-list-runs.sh NucleOS/nucleo-infra --limit 3
Limitaciones conocidas de la API de Gitea 1.24
- No hay endpoint global de runs:
/actions/runs404. Usamos/actions/tasksque sí existe pero solo aceptapage+limit— los demás filtros (workflow, branch, status, event) son client-side. - No hay endpoint para listar jobs de un run:
/actions/runs/{id}/jobs404. La skill hace probe de job_ids entask_id ± 10matcheando la primera línea del log conreceived task <task_id>. Si tu run tiene múltiples jobs o el offset es mayor, falla — pasale--job <jid>directo. - Logs por job son texto plano (
/actions/jobs/{job_id}/logs). Logs por run completo (/actions/runs/{id}/logs) devuelven zip — la skill nunca los toca porque no son procesables desde Bash sin extraer. - Actor del run no expuesto:
/actions/tasksno devuelve quién disparó el run. Si querés saber quién mergeó, mirá el merge commit congit log.
Qué NO hace esta skill
- No mergea PRs (out of scope; disruptive — dispara deploy a prod, requiere
confirmación explícita del usuario y prefijar
query.shmanualmente). - No comenta PRs (POST a issues/comments — out of scope; el PAT tampoco tiene scope para issues por default).
- No gestiona issues, releases, webhooks ni runners. Out of scope.
- No lee zip de logs run-level. Sólo job-level texto plano.
- No hace AI attribution en commits ni PRs. Imposible de bypassear desde esta skill (regla dura).
Archivos de la skill
| Archivo | Qué tiene |
|---|---|
SKILL.md |
Este archivo |
endpoints.md |
Cheat sheet de la API de Gitea 1.24 (lo relevante) |
.env.example |
Plantilla de config |
.env |
Generado por setup.sh (NO versionado, contiene el PAT) |
scripts/setup.sh |
Extrae PAT de bitwarden + valida |
scripts/query.sh |
Helper REST con admin guard |
scripts/pr-*.sh |
Wrappers de PRs |
scripts/actions-*.sh |
Wrappers de Gitea Actions |
Referencias
- API spec oficial Gitea: https://docs.gitea.com/api/1.24/
- Swagger JSON de la instancia:
https://gitea.nucleoriofrio.com/swagger.v1.json endpoints.md— cheat sheet de los endpoints relevantes