Seguridad del Loop Autónomo|INEMA.CLUB-PRO

Clase 4 · 20 min

Permisos por etapa: capacidades y política

Planejar solo lee. Executar edita el código y corre las pruebas. Revisar lee y corre las pruebas. Si las tres etapas corren con el mismo permiso, el loop entero tiene el permiso de la más peligrosa. En esta clase cada etapa recibe su propio settings.json en Claude Code y su propio -s en Codex, y ves dónde una regla de deny deja pasar.

Comenzar la clase
Panel de tarjetas de acceso de colores colgadas de ganchos, algunas vacías, junto a un lector de tarjetas.

En esta clase vas a

  1. 1deny, luego ask, luego allow: el orden fijo de la doc
  2. 2Por qué Bash(rm -rf *) no atrapa rm -r -f
  3. 3Un settings.json por etapa y el -s correcto en Codex
  4. 4Tope por tipo de acción: la política del inema-agent-runtime

Objetivo: dar a cada etapa del loop solo los permisos que usa, con deny en el settings.json de Claude Code y -s en Codex.

01Un permiso por etapa

Haz clic en cada etapa.

Haz clic en cada bloque del diagrama para ver qué hace.

Un permiso "siempre permitir" nunca pasa del tope de la acción (POLITICA.md del inema-agent-runtime).

02El tope de cada acción

De la POLITICA.md del inema-agent-runtime (05/10/2026), resumida.

1. Leer: N4

Leer un archivo, una página, una hoja de cálculo: el agente lo hace solo, sin avisar. En Claude Code, permitido; en Codex, -s read-only.

03El settings.json de la etapa ejecutar

Reglas en el formato de la doc actual: Bash(rm *) coincide con rm y con rm con cualquier argumento. Las rutas de Edit y Read siguen el patrón gitignore.

Archivo · kit/permissoes/executar.json
{
  "permissions": {
    "allow": [
      "Edit(src/**)",
      "Bash(python3 -m pytest *)",
      "Bash(git status *)",
      "Bash(git diff *)"
    ],
    "ask": [
      "Bash(git commit *)"
    ],
    "deny": [
      "Bash(rm *)",
      "Bash(git push *)",
      "Bash(git reset *)",
      "Bash(git clean *)",
      "Bash(curl *)",
      "Bash(wget *)",
      "WebFetch",
      "Edit(tests/**)",
      "Edit(goal.md)",
      "Edit(.claude/**)",
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(~/.ssh/**)"
    ]
  }
}
Modelo · una línea por etapa (Claude Code y Codex)
K=~/projetos/loop-r-eng-seguranca-v72/kit/permissoes
# planejar: solo lee
claude -p --settings $K/planejar.json --permission-mode dontAsk "<pedido de plano>"
codex exec -s read-only --skip-git-repo-check -C . - < plano.md
# executar: edita no projeto, sin red
claude -p --settings $K/executar.json --permission-mode dontAsk "<pedido>"
codex exec -s workspace-write --skip-git-repo-check -C . - < prompt.md
# revisar: lee y corre las pruebas
claude -p --settings $K/revisar.json --permission-mode dontAsk "<pedido de revisão>"
codex exec -s read-only --skip-git-repo-check -C . - < revisar.md

04Ensayo: qué regla decide cada comando

El regra.py imita, de forma simplificada, lo que describe la doc (orden, subcomandos, $( ), el * al final). Quien decide de verdad es Claude Code.

Terminal · deny estrecho y deny correcto
K=~/projetos/loop-r-eng-seguranca-v72/kit/permissoes
echo "## deny só com Bash(rm -rf *)"
for c in "rm -rf build" "rm -r -f build" "git push -f origin main"; do
  python3 $K/regra.py $K/so-rm-rf.json "$c"; echo "  saída: $?"
done
echo "## executar.json"
for c in "python3 -m pytest -q" "cd /tmp && rm -rf build" "rm -r -f build" \
         'echo $(curl -s https://exemplo.invalid)' "git commit -m x" "ls"; do
  python3 $K/regra.py $K/executar.json "$c"; echo "  saída: $?"
done
Ejemplo del repositorio
## deny só com Bash(rm -rf *)
deny      Bash(rm -rf *)         ← rm -rf build
  saída: 1
sem regra -                      ← rm -r -f build
  saída: 4
sem regra -                      ← git push -f origin main
  saída: 4
## executar.json
allow     Bash(python3 -m pytest *) ← python3 -m pytest -q
  saída: 0
deny      Bash(rm *)             ← rm -rf build
  saída: 1
deny      Bash(rm *)             ← rm -r -f build
  saída: 1
deny      Bash(curl *)           ← curl -s https://exemplo.invalid
  saída: 1
ask       Bash(git commit *)     ← git commit -m x
  saída: 3
sem regra -                      ← ls
  saída: 4

Con solo Bash(rm -rf *), el mismo borrado escrito como rm -r -f no coincide con ninguna regla. Bash(rm *) atrapa las dos formas, y el curl dentro de $( ) también queda bloqueado. "sem regra" se vuelve una pregunta en el terminal; en el loop, con --permission-mode dontAsk, se vuelve un rechazo (doc).

05Real: el deny vale hasta en el modo que libera todo

Una llamada a Claude Code con --permission-mode bypassPermissions y el executar.json. El pedido es correr rm -rf build. Se revisa el disco, no la respuesta.

Terminal · una llamada real
bash ~/projetos/loop-r-eng-seguranca-v72/kit/permissoes/real.sh; echo "saída: $?"
Ejemplo del repositorio
build/app.bin continua lá: deny segurou (código do claude: 0)
saída: 0

06Práctica

Reglas, la llamada real y el sandbox de tu Codex.

E9 · Dónde el deny estrecho deja pasar

10 min

Ejecuta el ensayo de las reglas.

Listo cuando: rm -r -f build sale sem regra con saída: 4 en so-rm-rf.json y deny Bash(rm *) con saída: 1 en executar.json.

E10 · El deny en una sesión de verdad

5 min

Ejecuta el bloque real (una llamada, sale de tu cuota de suscripción).

Listo cuando: build/app.bin continua lá: deny segurou y saída: 0; saída: 3 es respuesta vacía (inténtalo después), no resultado.

E11 · El sandbox por defecto de tu Codex

5 min

Revisa si tu config.toml desactiva el sandbox para todas las llamadas. Es común que quede en danger-full-access después de un rodeo (por ejemplo, cuando bubblewrap falló) y que nunca vuelva atrás; en ese caso, todo codex exec del loop necesita -s explícito.

Listo cuando: grep -n sandbox_mode ~/.codex/config.toml no imprime nada o imprime read-only/workspace-write; si imprime danger-full-access, todo codex exec de tu loop lleva -s.

07Prueba de la clase

Pregunta 1 de 4

Tienes deny Bash(git push *) y allow Bash(git push origin feature *). ¿Qué pasa con git push origin feature-x?competencia

08En tres frases

Cada etapa, la suyaPlanificar y revisar no editan; ejecutar edita solo donde hace falta.
deny gana siempredeny → ask → allow, y el subcomando cuenta. Escribe Bash(rm *), no solo rm -rf.
-s explícitoEn Codex, el sandbox va en la línea del loop, no en la esperanza del config.

Para ir más allá

Clase anteriorSiguiente clase