# De audit a enforce

> Construye la lista de permitidos de un job a partir de ejecuciones en audit, compruébala en las pull requests y aplícala sin romper el pipeline.

Una política nueva empieza en `audit`: no se rechaza nada y el resumen del job muestra lo que `enforce` rechazaría. Cuando el resumen sale limpio en los jobs que te importan, `enforce` rechaza el resto.

## 1. Ejecuta en audit

```yaml
version: 1
mode: audit
presets: [github-actions]
allow: []
```

Ejecuta al menos una vez cada workflow que use la acción, incluidos los jobs que solo corren en `main`, en etiquetas o programados: los destinos de un job dependen de lo que hace.

## 2. Copia los nombres

Cada resumen de job tiene un bloque plegado, **Names outside the policy**, ya en YAML:

```yaml
allow:
  - proxy.golang.org
  - sum.golang.org
  - registry.npmjs.org
```

Añádelos a `allow` después de comprobar que cada uno es esperado. Un nombre que no reconoces es justo lo que buscas: averigua qué paso llegó a él antes de permitirlo. La columna **Via** ayuda: `direct` quiere decir que una herramienta ignoró `HTTPS_PROXY`, y `container` da el nombre del contenedor.

Cambia varios nombres de un mismo dominio por un comodín solo cuando los nombres varían entre ejecuciones (fragmentos de CDN, hosts por región). `*.example.com` permite cualquier nombre por debajo de `example.com`, que es más de lo que necesita el job.

## 3. Compruébala en las pull requests

La entrada `mode` manda sobre el fichero, así que una misma política puede aplicarse en las pull requests mientras `main` solo informa:

```yaml
- uses: openwaf-dev/egress-action@v0.3.2
  with:
    mode: ${{ github.event_name == 'pull_request' && 'enforce' || 'audit' }}
```

Una conexión rechazada hace fallar el paso que la hizo (la herramienta recibe un `403`, un `NXDOMAIN` o un reset), y el resumen dice qué nombre y por qué.

## 4. Aplícala

Pon `mode: enforce` en el fichero. En un job de un runner de GitHub, pide también el bloqueo y que todos los contenedores cumplan la política:

```yaml
- uses: openwaf-dev/egress-action@v0.3.2
  with:
    lock: "on"
    containers: lock-all
```

Con `lock: "on"`, el paso falla si no se llega a root, en vez de seguir solo con el proxy; en enforce, un bloqueo que no se instala también hace fallar el paso. `lock-all` es seguro en los runners de GitHub, que ejecutan un job por máquina.

## Mantener la política al día

- **Una dependencia o herramienta nueva:** la primera ejecución en enforce falla en el nombre nuevo; el resumen da la línea para `allow`.
- **Un nombre que solo aparece a veces:** ejecuta el job en audit (con la entrada `mode`) varias veces y compara los resúmenes.
- **Desactivarla rápido:** pon `mode: audit` en la entrada o en el fichero. Para hacerlo sin commit, lee el modo de una variable del repositorio: `mode: ${{ vars.EGRESS_MODE || 'enforce' }}`, y después `gh variable set EGRESS_MODE -b audit`.

## Solución de problemas

| Síntoma | Causa y solución |
|---|---|
| `policy .github/egress.yml not found` | La acción se ejecuta antes de `actions/checkout`, o el fichero está en otra ruta: usa la entrada `policy`. |
| `field … not found in type main.Policy` | Una errata en una clave de `egress.yml`. |
| `enforce needs the lock` | Se llegaba a root pero no se pudo instalar el bloqueo nftables, normalmente porque falta `nft` en un runner self-hosted. Ver [runners self-hosted](https://developers.openwaf.dev/es/egress/ci/self-hosted-runners/#requirements). |
| `lock: on needs sudo or Docker` | `lock: "on"` en un runner donde el usuario del job no tiene ni `sudo` sin contraseña ni Docker. |
| Una herramienta falla con un error de certificado | El host está en `inspect` y la herramienta no lee las variables de la CA. Ver [Inspección y DLP](https://developers.openwaf.dev/es/egress/ci/inspect-and-dlp/#the-tls-trade-off). |
| El paso de caché va lento o se rechaza | Necesita el preset `github-actions`: la caché de Actions usa las cuentas de almacenamiento de GitHub. |
| Un nombre permitido se rechaza con `name_ip_mismatch` | La conexión fue a una dirección que ese nombre no resuelve: una entrada de `/etc/hosts`, una dirección escrita a mano o el DNS sobre HTTPS propio de una herramienta. Deja que la herramienta resuelva el nombre con el resolvedor del sistema. |
