---
name: infra-github-actions
description: >
  GitHub Actions CI/CD para proyectos que usan swl-ses. Cubre los tres workflows
  distribuidos (swl-security.yml, swl-ci.yml, release-please.yml), setup del secret
  CLAUDE_API_KEY, branch protection y troubleshooting. Cargar cuando se configura
  CI/CD con GitHub Actions en un proyecto donde está instalado swl-ses.
version: "1.0.0"
exclusiones:
  - "No cargar para otros sistemas CI/CD (GitLab CI, CircleCI, Jenkins) — este skill cubre solo GitHub Actions; para GitLab usar el workflow YAML estándar de GitLab."
  - "No cargar para configuración de pipelines internos del repo swl-ses — esos están en .github/workflows/ y no son distribuibles a usuarios."
  - "No cargar para troubleshooting de runners self-hosted — este skill asume GitHub-hosted runners; runners propios requieren guía aparte."
  - "No cargar para definir nuevos workflows desde cero sin relación con swl-security/swl-ci/release-please — para workflows custom usar la documentación oficial de GitHub Actions."
---

# infra-github-actions — GitHub Actions con swl-ses

## Cuándo cargar

- Al ejecutar `/swl:configurar-ci init` y necesitar guía de setup
- Al depurar un workflow que no dispara o falla por API key
- Al configurar branch protection en el proyecto
- Al decidir si adoptar release-please vs el flujo manual actual

## Cuándo NO cargar

- El proyecto usa Azure DevOps Pipelines o GitLab CI — esos tienen su propia configuración
- El objetivo es Kubernetes, Terraform o infraestructura cloud (cargar `kubernetes-orquestacion` o `terraform-experto`)
- La tarea es solo correr tests localmente sin CI
- El proyecto no usa GitHub como repositorio

---

## Workflows distribuidos por swl-ses

| Archivo | Propósito | Secrets requeridos |
|---------|-----------|-------------------|
| `swl-security.yml` | Revisión semántica de seguridad con Claude en cada PR | `CLAUDE_API_KEY` |
| `swl-ci.yml` | Lint + tests en push y PRs. Node 22+24, Python/Rust/Go comentados | Ninguno |
| `release-please.yml` | Release PR automático + tag + GitHub Release | Ninguno (`GITHUB_TOKEN` automático) |

Instalación con: `/swl:configurar-ci init`

---

## Reglas obligatorias

**NUNCA** commitear API keys en código ni en archivos de workflow.
Todo secret va en GitHub Settings → Secrets and variables → Actions.

**Permisos mínimos siempre**: declarar solo `contents: read` y `pull-requests: write`
en el nivel del workflow. Nunca `permissions: write-all`.

**Los workflows de forks externos no reciben secrets** por diseño de GitHub.
La revisión de seguridad con Claude solo funciona en PRs desde ramas del mismo repo,
no desde repos forked. Es un comportamiento de GitHub, no un bug.

**No hardcodear nombres de rama** más allá de `main`. Si el proyecto usa otra rama
por defecto, editar el `on: push: branches` en los workflows copiados.

---

## Setup de CLAUDE_API_KEY

1. Ir a https://console.anthropic.com y crear o copiar la API key
2. En GitHub: Settings → Secrets and variables → Actions → New repository secret
   - Nombre: `CLAUDE_API_KEY`
   - Valor: la API key
3. La key necesita permisos tanto para Claude API como para Claude Code

Verificar con gh CLI si el secret ya existe:
```bash
gh secret list | grep CLAUDE_API_KEY
```

Para configurar vía CLI (valor desde stdin, no queda en historial):
```bash
gh secret set CLAUDE_API_KEY
```

---

## Branch protection

Aplicar después de tener CI funcionando. El script del repo swl-ses:

```bash
# Ver qué haría sin aplicar cambios
node scripts/configurar-branch-protection.js --dry-run

# Aplicar
node scripts/configurar-branch-protection.js
```

Requiere `gh` CLI autenticado y permisos de admin en el repositorio.

Configura: require PR, status checks (`test (22)`, `test (24)`, `smoke`),
1 approval, bloquea force-push y deletions.

---

## Adoptar release-please (opt-in)

Ver `docs/RELEASE-PLEASE-MIGRATION.md` para comparativa completa.

El flujo actual del repo swl-ses usa `scripts/publicar.js` (manual). release-please
es una alternativa automática viable para proyectos de usuarios.

Instalar:
```
/swl:configurar-ci --with-release-please
```

Una vez activo, el flujo es:
1. Hacer merge de commits convencionales a main
2. release-please abre un "Release PR" automático con bump de versión y CHANGELOG
3. Al mergear ese PR → tag git + GitHub Release creado automáticamente

---

## Gotchas / Errores comunes no obvios

**GitHub Free + repo privado → 403 en branch protection Y Rulesets**: tanto el endpoint legacy
`/repos/.../branches/{}/protection` como el endpoint moderno `/repos/.../rulesets` requieren
**plan de pago** en repos privados (HTTP 403 "Upgrade to GitHub Pro or make this repository public"
en ambos). Mi documentación inicial afirmó incorrectamente que Rulesets era gratis para repos
privados Free — verificación empírica posterior confirmó que NO. Ambos endpoints están bloqueados.

Planes que destraban la feature en privado:
- **Pro** ($4/mes): aplica a repos en cuenta personal del titular Pro.
- **Team** ($4/usuario/mes): aplica solo a repos **de la organización** que paga Team. NO aplica
  a repos en la cuenta personal del admin de la org. Para que Team aplique al repo, transferirlo:
  `gh repo transfer cuenta-personal/repo --new-owner org`.

Sin plan de pago y manteniendo repo privado, las opciones son: pre-push hook local
(bypasseable con `--no-verify`) y workflow advisory (no bloquea push, crea issue post-hoc).

**Push directo a main bloqueado tras activar branch protection**: si configuraste
branch protection antes de que tu usuario tuviera al menos un PR mergeado con los
status checks pasando, el repo puede quedar en estado donde nadie puede mergear.
Causa: GitHub verifica los status checks declarados antes de permitir el merge; si
los checks no han corrido en el branch, el botón de merge queda bloqueado.
Fix: crear una rama temporal con un cambio trivial, abrir PR, dejar que los checks
corran, y mergear. Luego ya funciona el flujo normal.

**GITHUB_TOKEN no puede aprobar su propio PR** al usar release-please: release-please
crea un Release PR con el GITHUB_TOKEN del bot — ese mismo token no puede aprobarlo
si el repo requiere al menos 1 approval humano. Causa: GitHub bloquea la auto-aprobación
con el token de Actions por defecto.
Fix: crear un Personal Access Token (PAT) con scope `repo` y usarlo en el workflow:
`token: ${{ secrets.MY_RELEASE_TOKEN }}`. O reducir el required approvals a 0 para
el Release PR (no recomendado en repos con múltiples contribuidores).

**`anthropics/claude-code-security-review@main` falla con "API key not set"**: el
secret `CLAUDE_API_KEY` no está configurado o el nombre no coincide exactamente.
La action es sensible a mayúsculas — `claude_api_key` (minúsculas) no funciona.
Fix: verificar con `gh secret list`. El nombre debe ser exactamente `CLAUDE_API_KEY`.

**El workflow `swl-ci.yml` pasa localmente pero falla en CI con "lint script not found"**:
el campo `lint` no está definido en `package.json` del proyecto del usuario. La plantilla
usa `npm run lint --if-present` precisamente para ser tolerante, pero si el proyecto
tiene un nombre distinto (ej: `eslint`, `check`) el step se salta silenciosamente.
Fix: agregar el script `"lint": "..."` en `package.json` o editar el workflow para usar
el nombre correcto.

**release-please genera changelog con commits `chore(release)` del repo padre swl-ses**:
si el proyecto del usuario adoptó los mensajes de commit de swl-ses que incluyen
`chore(release): v5.X.Y`, release-please los interpreta como commits de release
y puede generar bumps incorrectos.
Fix: usar mensajes de commit convencionales estándar para el proyecto del usuario,
separados del estilo de swl-ses. Los prefijos `feat:`, `fix:`, `chore:` sin el
patrón `(release): vX.Y.Z` no causan conflicto.
