Novidades da v0.4.8
🇬🇧 English version · 📋 CHANGELOG completo · 📦 Baixar
Segurança no topo. Quem está na v0.4.7 executa bash no host sem
fronteira de allowlist. A v0.4.8 estreia o modo HostComAllowlist (#1272): a
agent.bash_allowlist deixa de ser dispensa de confirmação e vira um limite
real. Junto, o wasmtime que alimenta o sandbox WASM sobe de 48.0.2 para
49.0.2 em dois passos (#1524, #1559) e fecha onze advisories.
A release também fecha o que a v0.4.7 tinha adiado: a página global Agents &
Permissions do Web Console (#1433) e o import/export da política de acesso
do WhatsApp (#1435). Em volta, religa os seis canais que o README já anunciava
(#1567), corrige o escape de aspas na allowlist do bash (#1579) e conserta a
resolução de provider LLM.
Bash no host com fronteira de allowlist (#1272)
Até a v0.4.7, a agent.bash_allowlist só dispensava a confirmação de um comando.
Fora de um sandbox docker/podman, não havia como rodar bash no host com
limite real.
O modo HostComAllowlist muda isso. Quando a config declara padrões de comando
(prefixo com * no fim, ou comando exato), o BashTool entra em modo
allowlist-only: a lista vira fronteira, e todo comando fora dela é negado
antes do tier arriscado. A denylist do safety_gate continua na frente de tudo.
É o caminho para dar shell ao agente num aparelho sem Docker — Android/Termux,
por exemplo.
Dois ajustes acompanham o modo:
- Aspas protegem a prosa do argumento (#1579). A varredura antiga tratava
parênteses,
;,|e$dentro de aspas como comando composto. Um comando com"(transcreva o conteúdo completo)"na mensagem era negado mesmo com o prefixo liberado. Agora a checagem segue a tokenização do shell: aspas simples literalizam tudo, aspas duplas mantêm ativos só crase, escape e$de expansão. Composto de verdade (;,&&, pipe,$(...), redirecionamento, nova linha) segue nunca casando. garraia doctormostra o shell do agente no Termux (#1560). Sem docker/podman (sempre o caso no Android) e semagent.bash_allowlist, o bloco Termux mostra o itemTool bashcomo aviso, com a receita do modo allowlist-only — em vez de o operador só descobrir pelo próprio agente. A descrição deHostComAllowlistemdoctor,/api/diagnosticsegarra_statusagora diz explicitamente "SEM sandbox".
wasmtime 49 fecha onze advisories (#1524, #1559)
O runtime WASM subiu em dois passos:
- 48.0.2 → 49.0.1 (#1524): fecha quatro advisories — combustível não
contabilizado em
call_refe no lifting de record dinâmico, exaustão de memória do host na escrita de corpo HTTP de saída, e pânico com datetime fora de faixa noset-timesdo filesystem WASI. Este passo eleva o piso de MSRV para 1.96, porque a árvore do cranelift 0.136.1 declararustc 1.96.0. - 49.0.1 → 49.0.2 (#1559): fecha sete advisories — três no
wasmtime(corrupção da heap do GC e estouro de buffer em callback async-lifted) e quatro nowasmtime-wasi(poll_oneoffburlando a contabilidade de combustível, memória alocada em excesso sem stdio,fd_readdircopiando padding não inicializado, e timestamp de filesystem anterior à epoch derrubando o host). Este passo não eleva o MSRV: a árvore do 49.0.2 segue emrustc 1.96.0.
Nenhum dos dois exigiu migração de API no garraia-plugins. O Security - cargo audit agendado tinha ficado vermelho com os sete advisories do segundo passo.
O Web Console fecha o que a v0.4.7 adiou (#1433, #1435)
A v0.4.7 deixou duas peças da Access Policy v2 em aberto. A v0.4.8 entrega as duas.
Página global Agents & Permissions (#1433). Generaliza a página WhatsApp
Access para um lugar só: cada principal e suas capacidades efetivas por canal,
pelo mesmo motor de política (ADR 0025) e pelo vocabulário do registro de
capacidades, sem lógica de autorização duplicada. A rota de leitura
GET /admin/api/permissions/overview devolve o perfil de execução, a legenda
das classes (cada uma marcada sensível ou não) e cada canal com a sua fonte de
política — hoje só o whatsapp_linked tem motor por principal, e os demais são
listados com honestidade. A página não edita: leva ao caminho único da página
WhatsApp Access. Conceder a um principal uma classe mutante que ele não tinha
passa a exigir confirmação explícita, enforçada no servidor: sem
confirm_elevation: true o endpoint recusa com 409.
Exportar e importar a política, sem segredo (#1435). garraia whatsapp access export e GET /admin/api/whatsapp/access/export produzem um documento
versionado montado campo a campo por allowlist — token, cofre e material de
sessão ficam de fora por construção. --redact-pii mascara as identidades para
os quatro últimos dígitos e marca o export como não-importável. O import
valida formato e versão, recusa export redigido, substitui a política inteira,
mostra o impacto por principal com --dry-run e exige confirmação explícita
para qualquer alargamento. A escrita é atômica, com backup para rollback, e vai
para o audit.
Os seis canais que o README anunciava voltam a contar (#1567)
README, README.pt-BR e o ROADMAP diziam que Google Chat, Microsoft Teams,
Matrix, LINE, IRC e Signal estavam "implementados no crate, wiring no gateway
pendente", e o badge anunciava "5 channels". Os seis já estavam ligados no build
default: o garraia-gateway liga as features de canal incondicionalmente e o
boot instancia os seis, sem cfg. O badge passa a 11, e a tabela de status
distingue o canal com cobertura unitária no crate do canal coberto por teste de
integração do gateway — que é a pendência real nomeada.
Voz: Chatterbox saudável e a Garra falando por iniciativa própria
- Chatterbox saudável deixa de ser reportado como fora do ar (#1538). A
sonda batia em
/gradio_api/config, rota que nenhuma versão do Gradio serve: com ummultilingual_app.pyde pé, o gateway dizia❌ tts-chatterboxe mantinha o modo voz desligado. A cadeia agora é/→/config→/gradio_api/info, para na primeira resposta 2xx, e é a mesma nos dois lugares que antes sondavam separado. O WARN da falha nomeia cada rota e o que ela respondeu. - Tool
telegram_send_voice(#1557). A Garra sintetiza o texto (até 1000 caracteres) com o TTS configurado e entrega como voice message no Telegram. O destino é a mesma decisão dotelegram_send, com teto próprio de 2 vozes por minuto por sessão. Falha de TTS vira erro explícito, sem fallback silencioso para texto; a tool some da lista quando falta TTS ou o canal está offline. docs/voice.mdganha "Known pitfalls with the stock app" (#1539). Duas armadilhas de quem sobe o app do Chatterbox pela primeira vez: a sonda de saúde na rota errada (corrigida acima) e os prompts de voz default, que são URLs passadas cruas aolibrosa.loade quebram a síntese.
LLM: o provider certo, e o erro que não é mais engolido
Uma série de defeitos fazia o gateway atender pelo provider errado, ou mentir sucesso numa resposta vazia. A v0.4.8 fecha todos (#1540, #1541, #1554):
- Dois perfis
llm:do mesmo tipo param de disputar um slot. Cada perfil passa a ser registrado pela chave (with_name), não pelo tipo. Antes, duas entradasprovider: openaicolidiam e o provider efetivo era sorteado a cada boot. Vale também paraanthropicellamacpp(#1554). - O fallback usa o modelo DELE. O laço repassava o
modeldo primário ao fallback, emodelé o nome que aquele backend entende — umopenrouterrecebendoglm53-flashrespondia400. Agora o fallback usa o modelo que a config já dizia para ele. - O SSE para de engolir o erro do provider. Em
stream: true, umErrdo turno era descartado e o stream terminava emfinish_reason: "stop"— uma resposta em branco com cara de sucesso. Agora o stream emite{"error": {...}}. POST /v1/chat/completionssemmodelpara de mandar"gpt-4". O corpo semmodelchega ao provider como o sentinel vazio que ele resolve com o próprio modelo configurado, e omodeldo response ecoa quem de fato atendeu.
Confiabilidade e operação
restartnão cria mais daemon órfão sob systemd (#1542). Uma instalação v0.4.6 chegou a 4606 reinícios em ~8h porque orestartmatava o daemon da unit e subia um processo por fora dela, brigando porAddress already in use. A CLI agora lê o cgroup de quem está na porta e, se for uma unit systemd, recusa antes de parar qualquer coisa (exit 78), nomeando osystemctl restartcerto. Escotilha:GARRAIA_ALLOW_SYSTEMD_RESTART=1.- A remediação do MCP aponta para um comando que existe (#1543). Os textos
diziam
garraia mcp restart <nome>, que o clap não conhece; agora apontam paraPOST /admin/api/mcp/<nome>/restart, o mesmo do botão Restart no console. Um teste varre o fonte para o comando fantasma não voltar. .mcp.jsonda raiz volta a subir o servidor MCP (#1536). A entrada apontava para./target/release/garra, caminho que só existe depois de um build e só resolve a partir da raiz do repo. Agora usagarradoPATH.
Qualidade: cobertura medida e um piso que derruba o build (#1566)
O .quality/baseline.json dizia coverage_pct: null em todo run — o job do
ratchet sempre olhava antes de o job de cobertura terminar. Agora a busca varre
os últimos runs por um completed+success e cai para o último verde de main
quando o SHA da PR ainda não fechou. O baseline passa a trazer 72,00% de
linha, medidos e gravados a partir do lcov.info — nunca à mão, o invariante
anti-fraude continua valendo.
Junto entra um piso de cobertura que reprova o build: o
scripts/ci/coverage_gate.py falha o job abaixo de 70,0%, lê o lcov.info
pelo mesmo parser que escreve o baseline, é fail-closed (ausente ou vazio
reprova) e roda como último step, para a reprovação nunca esconder a informação
de quem vai consertar. O AI Quality Ratchet segue report-only: nenhuma PR é
bloqueada por ele.
Como atualizar
garra update # CLI; guarda a versão anterior e aceita `garra rollback`
Instalação nova segue pelo instalador de sempre.
Limites conhecidos
- Instaladores do Windows e bundles de desktop continuam não assinados — o SmartScreen avisa na primeira execução do MSI.
- O auto-updater do desktop Tauri segue desativado; o caminho de atualização
suportado é o
garra updateda CLI. - Os seis canais religados (#1567) têm cobertura unitária no crate, mas ainda falta teste de integração do gateway para eles.