Segurança do Loop Autônomo|INEMA.CLUB-PRO

Aula 4 · 20 min

Permissões por etapa: capacidades e política

Planejar só lê. Executar edita o código e roda os testes. Revisar lê e roda os testes. Se as três etapas rodam com a mesma permissão, o loop inteiro tem a permissão da mais perigosa. Nesta aula cada etapa ganha o próprio settings.json no Claude Code e o próprio -s no Codex, e você vê onde uma regra de deny deixa passar.

Começar a aula
Painel de cartões de acesso coloridos pendurados em ganchos, alguns vazios, ao lado de uma leitora de cartão.

Nesta aula você vai

  1. 1deny, depois ask, depois allow: a ordem fixa da doc
  2. 2Por que Bash(rm -rf *) não pega rm -r -f
  3. 3Um settings.json por etapa e o -s certo no Codex
  4. 4Teto por tipo de ação: a política do inema-agent-runtime

Objetivo: dar a cada etapa do loop só as permissões que ela usa, com deny no settings.json do Claude Code e -s no Codex.

01Uma permissão por etapa

Clique em cada etapa.

Clique em cada bloco do diagrama para ver o que ele faz.

Uma permissão "sempre permitir" nunca passa do teto da ação (POLITICA.md do inema-agent-runtime).

02O teto de cada ação

Da POLITICA.md do inema-agent-runtime (05/10/2026), resumida.

1. Ler: N4

Ler arquivo, página, planilha: o agente faz sozinho, sem aviso. No Claude Code, permitido; no Codex, -s read-only.

03O settings.json da etapa executar

Regras no formato da doc atual: Bash(rm *) casa rm e rm com qualquer argumento. Caminhos de Edit e Read seguem padrão gitignore.

Arquivo · 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 · uma linha por etapa (Claude Code e Codex)
K=~/projetos/loop-r-eng-seguranca-v72/kit/permissoes
# planejar: só lê
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, sem rede
claude -p --settings $K/executar.json --permission-mode dontAsk "<pedido>"
codex exec -s workspace-write --skip-git-repo-check -C . - < prompt.md
# revisar: lê e roda os testes
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

04Ensaio: que regra decide cada comando

O regra.py imita, simplificado, o que a doc descreve (ordem, subcomandos, $( ), o * no fim). Quem decide de verdade é o Claude Code.

Terminal · deny estreito e deny certo
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
Exemplo do repositório
## 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

Com só Bash(rm -rf *), o mesmo apagar escrito como rm -r -f não casa nenhuma regra. Bash(rm *) pega as duas formas, e o curl dentro de $( ) também é barrado. "sem regra" vira pergunta no terminal; no loop, com --permission-mode dontAsk, vira recusa (doc).

05Real: o deny vale até no modo que libera tudo

Uma chamada ao Claude Code com --permission-mode bypassPermissions e o executar.json. O pedido é rodar rm -rf build. Confere-se o disco, não a resposta.

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

06Prática

Regras, a chamada real e o sandbox do seu Codex.

E9 · Onde o deny estreito deixa passar

10 min

Rode o ensaio das regras.

Pronto quando: rm -r -f build sai sem regra com saída: 4 no so-rm-rf.json e deny Bash(rm *) com saída: 1 no executar.json.

E10 · O deny numa sessão de verdade

5 min

Rode o bloco real (uma chamada, sai da sua cota).

Pronto quando: build/app.bin continua lá: deny segurou e saída: 0; saída: 3 é resposta vazia (tente depois), não resultado.

E11 · O sandbox padrão do seu Codex

5 min

Veja se o seu config.toml desliga o sandbox para todas as chamadas. É comum ele ficar em danger-full-access depois de um contorno (por exemplo, quando o bubblewrap falhou) e nunca mais voltar; nesse caso, todo codex exec do loop precisa de -s explícito.

Pronto quando: grep -n sandbox_mode ~/.codex/config.toml não imprime nada ou imprime read-only/workspace-write; se imprimir danger-full-access, todo codex exec do seu loop leva -s.

07Teste da aula

Pergunta 1 de 4

Você tem deny Bash(git push *) e allow Bash(git push origin feature *). O que acontece com git push origin feature-x?competência

08Em três frases

Cada etapa, a suaPlanejar e revisar não editam; executar edita só onde precisa.
deny ganha sempredeny → ask → allow, e subcomando conta. Escreva Bash(rm *), não só rm -rf.
-s explícitoNo Codex, o sandbox vai na linha do loop, não na esperança do config.

Para ir além

Aula anteriorPróxima aula