Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
cplt — Sandbox para agentes de codificação de IA. Executa Copilot CLI, Claude Code, OpenCode, Gemini CLI, Antigravity, Pi, goose ou um shell simples dentro de um sandbox em nível de kernel, com proteções de git e gh e política de sandbox versionada no repositório. | Kitploit
Ferramentas/GitHubGitHub/navikt/cplt
Ferramentas DefensivasAnálise Dinâmica (Sandboxing)Auditoria de ConfiguraçãoVirtualização para SegurançaDevSecOpsComando e ControleUtilitários e FrameworksDetecção de SegredosSegurança da Cadeia de SuprimentosSegurança de IA
12123130há 2 diasRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
GitHub
navikt/cplt

cplt

Sandbox para agentes de codificação de IA. Executa Copilot CLI, Claude Code, OpenCode, Gemini CLI, Antigravity, Pi, goose ou um shell simples dentro de um sandbox em nível de kernel, com proteções de git e gh e política de sandbox versionada no repositório.

Ver RepositórioSite
Compartilhar

cplt

CI Release License: MIT macOS Linux

Sandbox imposto pelo kernel para agentes de codificação de IA. O cplt envolve o GitHub Copilot CLI, OpenCode, Gemini CLI, Antigravity CLI, Pi, Claude Code, goose, DeepSeek Harness, ou qualquer shell, para que o agente possa escrever código mas não possa roubar credenciais, fazer push para a main, fazer merge de PRs ou exfiltrar segredos.

  • macOS: Apple Seatbelt/SBPL via sandbox-exec
  • Linux: Landlock LSM + seccomp-BPF + isolamento opcional de namespaces com Bubblewrap (kernel 5.13+, filtragem de rede completa no 6.7+)
  • Windows: sem suporte nativo. Não existe backend de sandbox para Windows. Execute o cplt dentro do WSL2, onde é uma instalação Linux comum e o kernel da Microsoft inclui o Landlock. Consulte Configuração do Windows (WSL2).

cplt banner

Por que o cplt?

Agentes de IA executam código arbitrário. Um agente comprometido, seja por injeção de prompt, ataque à cadeia de suprimentos ou um servidor MCP malicioso, pode ler ~/.ssh, fazer push para a main, fazer merge de PRs ou exfiltrar seu código, a menos que o próprio sistema operacional diga não.

O cplt oferece imposição em nível de kernel com política configurável pela equipe:

  • Política por repositório em .cplt.toml, versionada no controle de versão, portanto à prova de adulteração e auditável
  • Negar por padrão para credenciais, segredos e arquivos sensíveis
  • Interceptação de git e gh em nível de comando: pushes para a branch padrão, force pushes, merges e releases são bloqueados, branches de feature permanecem abertas
  • Filtragem de rede de saída com log de auditoria
  • Sem Docker, sem VMs. Um único binário que roda em um laptop com restrições rígidas
  • Início sem configuração para desenvolvedores, com válvulas de escape quando um build realmente precisa de uma

Índice

  • Início rápido
  • O que ele bloqueia
  • Como o cplt se compara
  • Instalação
  • Uso
  • Configuração
  • Arquitetura
  • Segurança
  • Rede e proxy
  • Guardas de comando
  • Impactos conhecidos
  • Limitações
  • Contribuindo
  • Referências

Documentação detalhada: Configuração · Proxy e filtragem de domínio · guarda de comando gh · guarda de comando git · Impactos conhecidos · Detalhes de segurança · Modelo de segurança

Início rápido```bash

brew install navikt/tap/cplt # macOS. On Debian or Ubuntu, see apt below cplt --shell-install # make 'copilot' run sandboxed (persistent) # --agent opencode for any other agent cplt doctor # check your environment cplt -- -p "fix the tests" # run Copilot in sandbox

root@kitploit:~
Outros agentes e comandos de sandbox:```bash
cplt --agent opencode                       # OpenCode (Copilot subscription)
cplt --agent opencode --pass-env ANTHROPIC_API_KEY  # third-party provider
cplt --agent shell                          # interactive sandboxed shell (no AI)
cplt exec -- npm install                    # sandbox any command directly
cplt exec -c "npm install && npm test"      # compound commands in sandbox
alias npm="cplt exec -- npm"               # sandboxed npm for every invocation

Implantação em equipe```bash

1. Generate per-repo policy

cplt init --write

2. Developers approve on first run

cplt trust accept --all

3. Tune the command guards (both block by default)

cplt config set git_guard.protect_default_branch_only false # block every push, not just main cplt config set git_guard.mode warn # observe instead of blocking

root@kitploit:~
## O que ele bloqueia

O sandbox bloqueia o acesso a credenciais e segredos no kernel. Guardas de comando bloqueiam operações destrutivas. Toda restrição se aplica ao agente e a todo processo que ele gera.

| Recurso | Status | Notas |
| --- | --- | --- |
| Ler/escrever diretório do projeto | ✅ Permitido | |
| Ler/escrever/apagar `.env*`, `.pem`, `.key` no projeto | 🔒 Bloqueado pelo kernel | Impede exfiltração e destruição de segredos. `--allow-env-files` sobrepõe |
| Escrever `.git/hooks`, `.git/config`, `.gitmodules` | 🔒 Bloqueado pelo kernel (macOS), ⚠️ parcial no Linux | Impede persistência via git hooks, redirecionamento de hooksPath, sequestro de submódulo. **Linux:** Landlock não consegue negar um subcaminho dentro de uma árvore permitida, então estes permanecem graváveis no caminho somente-Landlock. `bwrap` re-vincula `.git/hooks` como somente leitura mas deliberadamente deixa `.git/config` e `.gitmodules` graváveis, então `core.hooksPath` permanece uma rota de persistência, veja [Limitações do Linux](https://github.com/navikt/cplt/blob/main/docs/security.md#linux). Aplica-se a **toda** raiz gravável, o projeto e cada concessão de `allow.write`, incluindo um worktree concedido ou repositório bare cujos hooks reais vivem fora de `<root>/.git` |
| Executar de `/tmp`, `/var/folders` | 🔒 Bloqueado pelo kernel | Impede escrever-depois-executar. O diretório de rascunho redireciona TMPDIR para um local seguro, ativado por padrão |
| Escrever diretórios bin/shim resolvidos via PATH (`~/.bun/bin`, `~/.deno/bin`, `$PNPM_HOME`, `shims/` do mise e todo o `installs/`) | 🔒 Bloqueado pelo kernel (macOS), ⚠️ mise parcial no Linux | Impede trojanizar um binário que seu próximo comando *não-sandboxed* resolve via PATH. Mesmo motivo pelo qual `~/.cargo/bin` e `~/go/bin` sempre foram somente leitura. Quebra `bun install -g`, `deno install`, `pnpm add -g`, `mise install`, `mise upgrade`, `mise use -g` dentro do cplt, deliberadamente, e um repositório fixando uma toolchain não instalada não faz mais bootstrap. Instalações locais ao projeto não são afetadas. **Linux:** os dois do mise usam a sobreposição somente-leitura do `bwrap`; o resto se mantém nativamente. Veja [Instalações globais de ferramentas](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#global-tool-installs) |
| Executar de `~/Library/Caches` | 🔒 Bloqueado pelo kernel por padrão | Impede preparação de entrega de binários. Módulos nativos do Copilot são isentos via uma exceção. Adicione isenções direcionadas com `--allow-cache-exec <SUBDIR>`, ex. `ms-playwright` |
| Modificar `.vscode/tasks.json`, `launch.json` | ⚠️ Permitido, risco conhecido | Fronteira de confiança da IDE. Veja [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md) para mitigações |
| Ler/escrever `~/.copilot` (auth, configurações) | ✅ Permitido | Inclui `file-map-executable` para `keytar.node`, `pty.node`, `computer.node` |
| Escrever `~/.copilot/pkg` (módulos nativos) | 🔒 Bloqueado pelo kernel | Impede persistência via substituição de módulo nativo |
| Variáveis de ambiente | 🔒 Sanitizadas + endurecidas | Apenas uma allowlist segura passa. Scripts de ciclo de vida bloqueados. `--pass-env VAR` adiciona uma de volta |
| Ler `~/.config/gh/hosts.yml` + `config.yml` | ✅ Permitido (somente leitura) | Apenas estes dois arquivos. O resto de `.config/gh` é bloqueado |
| Ler `~/.config/mise` | ✅ Permitido (somente leitura) | Versões de ferramentas e PATH, sem segredos |
| Ler `~/.gitconfig`, `~/.config/git/config` | ✅ Permitido (somente leitura) | Um symlink de dotfiles é seguido até seu alvo, então um `~/.gitconfig` stowed funciona |
| Ler `~/.git-credentials` | 🔒 Bloqueado pelo kernel | `credential.helper = store` mantém tokens em texto claro aqui. Nenhum `--allow-read` reabre, como `~/.netrc`. **Linux:** uma concessão em um *ancestral* (`$HOME` em si) ainda o expõe, porque Landlock não consegue negar um subcaminho dentro de uma árvore permitida |
| Ler hooks globais do git (`core.hooksPath`) | ✅ Permitido (somente leitura, escrita negada) | Auto-detectado. Deve estar sob `$HOME` com profundidade ≥3. Escritas são explicitamente bloqueadas |
| Assinatura de commit/tag (`commit.gpgsign`, `tag.gpgsign`) | 🔒 Desabilitado | Chaves privadas em `~/.ssh` e `~/.gnupg` são bloqueadas, então a assinatura é desabilitada via uma sobreposição de variável de ambiente |
| Ler `~/Library/Application Support/Microsoft` | ✅ Permitido (somente leitura) | Device ID para telemetria |
| Acessar macOS Keychain | ⚠️ Permitido (leitura+escrita) para agentes que armazenam auth lá | A concessão não pode ser limitada a um item, então alcança toda entrada do keychain que o agente consegue desbloquear. Opte por `sandbox.keychain_substitute` (EXPERIMENTAL, padrão desligado) para descartá-lo em execuções onde o agente consegue autenticar sem ele — `CLAUDE_CODE_OAUTH_TOKEN` para Claude Code, um arquivo de token de fallback existente para Antigravity. Veja [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md#keychain-access-is-all-or-nothing) |
| Rede de saída (porta 443) | ✅ Permitido | Toda outra porta é bloqueada. Adicione extras com `--allow-port` |
| Saída para localhost | 🔒 Bloqueado pelo kernel (macOS), ⚠️ baseado em porta no Linux | Impede acesso a serviço local. Entrada ainda funciona para o proxy. **Linux:** regras do Landlock são apenas números de porta e não conseguem distinguir `localhost:443` de `remote:443`, então um serviço local em uma porta permitida é alcançável e não há negação específica para localhost. Use `--with-proxy` para proteção SSRF, veja [Limitações do Linux](https://github.com/navikt/cplt/blob/main/docs/security.md#linux) |
| SSH agent (unix socket) | 🔒 Bloqueado pelo kernel (macOS), ⚠️ apenas env no Linux | Impede assinatura de operações git ou SSH para hosts. **Linux:** `connect()` de unix socket não é controlado, então o `SSH_AUTH_SOCK` retido é a única barreira e um agente que o define por conta própria pode usar as chaves carregadas. `bwrap` esconde o socket OpenSSH padrão sob `/tmp`, mas não um agente gnome-keyring/gcr ou systemd sob `$XDG_RUNTIME_DIR`. Veja [Limitações do Linux](https://github.com/navikt/cplt/blob/main/docs/security.md#linux) |
| Ferramentas de desenvolvimento (`~/.cargo`, `~/.gradle`, `~/.m2`, `~/.sdkman`, `~/.jenv`, `~/.pyenv`, `~/.konan`, etc.) | ✅ Permitido (leitura+escrita para caches) | Apenas diretórios que existem no disco. Ajustado em tempo de execução pelo que `cplt doctor` detecta |
| Arquivos de credencial de registro (`~/.m2/settings.xml`, `~/.gradle/gradle.properties`, `~/.cargo/credentials`) | 🔒 Bloqueado pelo kernel no macOS. No Linux o diretório pai da ferramenta permanece legível | Sobrepõe com `--allow-read`. Veja [Registros privados](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#private-registries) |
| Ler `~/.npmrc` | 🔒 Bloqueado pelo kernel (ambas plataformas) | Sobrepõe com `--allow-read`. Quebra yarn 1, veja [yarn 1](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#yarn-1-and-unreadable-home-rc-files) |
| Código-fonte Go (`~/go/src`) | 🔒 Bloqueado pelo kernel | Apenas `~/go/bin` e `~/go/pkg` são legíveis |
| Ler `~/.ssh`, `~/.gnupg`, `~/.aws`, `~/.azure` | 🔒 Bloqueado pelo kernel | |
| Ler `~/.kube`, `~/.docker`, `~/.nais` | 🔒 Bloqueado pelo kernel | |
| Ler `~/.password-store`, `~/.terraform.d` | 🔒 Bloqueado pelo kernel | |
| Ler `~/.config/gcloud`, `~/.config/op` | 🔒 Bloqueado pelo kernel | Arquivos individuais são sobreponíveis com `--allow-read`. Veja [Credenciais de nuvem](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#cloud-credential-directories) |
| Ler ou escrever `~/.config/cplt`, `~/.nav-pilot` | 🔒 Bloqueado pelo kernel | Estado da ferramenta que decide o que o *próximo* lançamento pode fazer. `~/.config/cplt` é não-sobreponível como uma subárvore inteira; dentro de `~/.nav-pilot`, um caminho nomeado permanece concedível para que um payload de agentpakke fixado possa ser lido |
| Ler `~/.netrc`, `~/.pypirc`, `~/.vault-token` | 🔒 Bloqueado pelo kernel | Não-sobreponível em ambas plataformas. Nomear um em `allow.read` é um erro de inicialização |
| Ler `~/.gem/credentials` | 🔒 Bloqueado pelo kernel | Não-sobreponível em ambas plataformas. Nomear um em `allow.read` é um erro de inicialização |
| Operações destrutivas do `gh` CLI (merge, delete, release) | 🔒 Controlado por comando (ativado por padrão) | Opte por sair com `--no-gh-guard`. Veja [gh guard](https://github.com/navikt/cplt/blob/main/docs/gh-guard.md) |
| `git push` para o branch padrão | 🔒 Controlado por comando (ativado por padrão) | Bloqueia pushes para `main`/`master`; pushes de feature-branch ainda funcionam. `protect_default_branch_only = false` bloqueia todo push, `git_guard.mode = "warn"` apenas avisa, `--no-git-guard` opta por sair |
| Herança de processo filho | ✅ Todas as restrições se aplicam a subprocessos | |

Essa tabela é um resumo. O sandbox também permite acesso a arquivos de sistema (certificados SSL, `/etc/hosts`), diretórios temporários (leitura e escrita, sem exec) e caminhos de ferramentas de sistema (`/usr/bin`, `/opt/homebrew`). Execute `cplt --print-profile` para as regras SBPL completas.

Para o modelo de segurança completo, análise de ameaças e estratégia de testes, leia [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md).

## Como o cplt se compara

### Sandbox do Codex CLI

| Área | cplt | Sandbox do Codex CLI |
| --- | --- | --- |
| Controle de rede de saída | Proxy CONNECT com listas de permitir/bloquear domínios | Sem filtragem em nível de domínio |
| Tratamento de ambiente | Allowlist mais injeção de env endurecida | Modelo de pass-through mais básico |
| Proteção de arquivos de segredo | Padrões de negação como `.env*`, `.pem`, `.key` dentro do repositório | Acesso primariamente com escopo de diretório |
| Política de repositório | [`.cplt.toml`](https://github.com/navikt/cplt/blob/main/docs/configuration.md#per-repo-configuration-cplttoml) com um fluxo explícito de confiança/aprovação | Sem arquivo de política em nível de repositório |
| Suporte a agentes | Copilot, OpenCode, Gemini CLI, Antigravity CLI, Pi, Claude Code, goose, DeepSeek Harness, ou shell | Apenas Codex |

O cplt não é mais forte em tudo. O Codex CLI tem isolamento de namespace Linux hoje, e já expõe modos de sandbox explícitos como somente leitura e workspace-write. O cplt ainda não tem essa matriz de modos.

### Sandboxes baseados em Docker

| Área | cplt | Sandbox baseado em Docker |
| --- | --- | --- |
| Tempo de inicialização | Praticamente instantâneo para uso normal de CLI | Inicialização de contêiner geralmente mais lenta |
| Controle de rede | Filtragem de saída por requisição via proxy | Acesso à rede geralmente tudo-ou-nada |
| Controles de arquivo | Regras por caminho e por padrão | Controles por montagem |
| Requisitos de host | Binário único | Daemon Docker necessário |
| Adequação a laptop corporativo | Funciona onde Docker é indisponível ou restrito | Frequentemente bloqueado por política local |

Docker ainda oferece isolamento mais forte em alguns ambientes, especialmente se você quer um sistema de arquivos e namespace de processo totalmente separados. O cplt troca isso por configuração mais leve e integração mais estreita com a máquina em que você já desenvolve.

### Permissões do modo agente do VS Code

Ferramentas como o modo agente do VS Code dependem principalmente de permissões de UI. O cplt impõe suas restrições no kernel, então o agente não pode contorná-las com um prompt ou uma instrução modificada. Isso importa mais para agentes de CLI e exposição de credenciais:

- o cplt funciona fora da IDE
- variáveis de ambiente são filtradas antes do agente iniciar
- arquivos sensíveis podem ser bloqueados mesmo quando vivem dentro do repositório
- as mesmas restrições se aplicam a processos filhos

### Sandbox do Claude Code (Anthropic Sandbox Runtime)

O [Anthropic Sandbox Runtime](https://github.com/anthropic-experimental/sandbox-runtime) (`srt`) é a camada de sandbox usada pelo Claude Code. Mesma abordagem de alto nível que o cplt, macOS Seatbelt mais imposição em nível de kernel no Linux mais um proxy HTTP, implementação diferente.

| Área | cplt | Anthropic srt |
| --- | --- | --- |
| Linguagem / entrega | Binário Rust único | Pacote Node.js + npm + deps externas |
| Backend Linux | Landlock LSM (sem deps, sem namespaces) | bubblewrap (contêiner via user namespaces) |
| Filtragem de ambiente | Allowlist estrita + negação por sufixo (`_TOKEN`, `_SECRET`) | Herda env pai completo (segredos passam) |
| Proteção de diretório de credenciais | 15+ diretórios negados por padrão | Usuário deve configurar manualmente |
| Proteção contra DNS rebinding | ✅ IP pós-DNS verificado contra faixas privadas | ❌ Não implementado |
| Proxy de rede | HTTP CONNECT + permitir/bloquear domínio | HTTP + SOCKS5 + TLS MITM experimental |
| SSH git | Bloqueado no kernel no macOS (socket do agente negado); no Linux apenas `SSH_AUTH_SOCK` é retido | Proxied via SOCKS5 |
| Scripts de gerenciador de pacotes | Bloqueados por padrão (`npm_config_ignore_scripts`) | Não bloqueados |
| Suporte a agentes | Copilot, OpenCode, Gemini, Antigravity, Pi, Claude Code, goose, DSH, Shell | Claude Code |
| Configuração | TOML (global + por repositório) | JSON (apenas global) + atualizações ao vivo via `--control-fd` |
| API de biblioteca | ❌ Apenas binário | ✅ Biblioteca TypeScript embutível |

O cplt é mais seguro pronto para uso: filtragem de env, proteção de credenciais, verificações de DNS rebinding, bloqueio de scripts de ciclo de vida. O srt é mais flexível: SOCKS5, inspeção TLS, callbacks por requisição, embutimento de biblioteca. A escolha do backend Linux importa. bwrap precisa de contornos no Ubuntu 24.04+ por causa das restrições de userns do AppArmor, enquanto Landlock requer kernel 5.13 ou mais novo mas tem zero dependências externas.

### O próprio sandbox do GitHub Copilot CLI

O Copilot CLI vem com um sandbox local desde junho de 2026, incluído na
assento padrão. Ele executa comandos de shell através do Microsoft MXC com
acesso restrito a sistema de arquivos, rede e sistema, no macOS, Linux e Windows.
`/sandbox enable` o ativa.

Se isso cobre você, use. Não custa nada extra, e roda no Windows,
que o cplt não roda.

Duas coisas que ele não faz.

A política vive com o administrador, não com o repositório. Empresas definem
política de sandbox através do Intune ou outro MDM. Nada fica ao lado do código,
então uma regra que importa para um repositório não pode segui-lo até um contribuidor,
até o CI, ou até um laptop que o MDM não gerencia. No cplt a política é
`.cplt.toml` no repositório. Revisores veem mudanças nele no pull
request, e o arquivo pode apertar a configuração do próprio desenvolvedor mas nunca
afrouxá-la.

Ele confina o processo, não o que o processo faz com credenciais que ele
detém. As abas `/sandbox` cobrem o sistema de arquivos, a rede e capacidades
de sistema, e dentro de um repositório Git o agente recebe leitura e escrita
em `.git` por padrão. Um agente em sandbox ainda tem seu token `gh` e seu
acesso de push. Fazer push de um branch, fazer merge de um pull request e apagar um
repositório são todas chamadas de API bem formadas de um cliente autorizado, e uma
regra de sistema de arquivos ou rede não tem opinião sobre elas. O cplt envolve `git` e
`gh` em vez disso. O agente faz commit, branch e rebase livremente. `gh pr merge`,
`gh repo delete` e `gh release create` são bloqueados por padrão. Também é
`git push` para `main`/`master`; pushes de feature-branch ainda funcionam, porque
`protect_default_branch_only` está ativado. Defina como `false` para bloquear todo push, ou
`git_guard.mode = "warn"` para apenas avisar.

Rodar ambos é razoável. O MXC confina o processo. As guardas decidem o que
o agente pode fazer com as credenciais que ele detém.

### Lacunas honestas

- macOS tem a imposição em nível de arquivo mais forte hoje. A cobertura Linux está melhorando mas não é idêntica.
- O cplt ainda não oferece presets simples de política somente leitura / workspace-write / acesso total.
- Se você quer isolamento total de contêiner, o cplt não está tentando substituir o Docker.

## Instalação

### Homebrew (recomendado)```bash
brew install navikt/tap/cplt

mise```bash

mise use -g 'github:navikt/cplt@'

root@kitploit:~
mise escolhe o asset de release correto para a sua plataforma e verifica a
atestação de proveniência de build.

Fixe a versão. Nossas strings de versão não são semver comparáveis — elas carregam
zeros à esquerda e dois hífens — então `mise latest` pode resolver para uma
release mais antiga do que a mais recente ([navikt/copilot#818](https://github.com/navikt/copilot/issues/818)).

### apt (Debian/Ubuntu, recomendado no Linux)

[navikt/apt](https://navikt.github.io/apt/) é um arquivo assinado servido via
GitHub Pages, contendo cplt e nav-pilot para amd64 e arm64:```bash
curl -fsSL https://navikt.github.io/apt/keyring/navikt-archive-keyring.gpg \
  | sudo tee /usr/share/keyrings/navikt-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/navikt-archive-keyring.gpg] https://navikt.github.io/apt stable main" \
  | sudo tee /etc/apt/sources.list.d/navikt.list
sudo apt update && sudo apt install cplt

É um espelho simples de repositório apt que espelha as nossas releases, não um pacote de distribuição com o seu próprio mantenedor. O seu job de publicação corre de hora a hora e puxa o .deb mais recente da última release de cada ferramenta, pelo que uma release cortada há minutos demora até uma hora a tornar-se instalável dessa forma.

O pacote coloca o binário em /usr/bin/cplt, e as atualizações seguem via sudo apt upgrade a partir daí. O cplt update recusa-se a tocar numa instalação apt e aponta para sudo apt upgrade em vez disso: substituir o binário pelas costas do dpkg seria desfeito na próxima execução do apt.

Sem o arquivo, o mesmo .deb é um recurso de release:```bash arch=$(dpkg --print-architecture) # amd64 or arm64 gh release download --repo navikt/cplt --pattern "${arch}.deb" sudo apt install ./cplt_"${arch}".deb

root@kitploit:~
### curl | bash

Para distribuições que não são derivadas do Debian, e para CI:```bash
curl -fsSL https://raw.githubusercontent.com/navikt/cplt/main/install.sh | bash

Opções:```bash

Install a specific version

curl -fsSL ... | bash -s -- --version 2026.05.05-174753-75bae5b

Install to a custom directory

curl -fsSL ... | bash -s -- --dir ~/.local/bin

Skip Homebrew (force direct download)

curl -fsSL ... | bash -s -- --no-brew

root@kitploit:~
### Baixar das releases

Pegue a build mais recente para a sua plataforma em [GitHub Releases](https://github.com/navikt/cplt/releases/latest):```bash
# macOS, Apple Silicon (M1/M2/M3/M4)
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-aarch64-apple-darwin.tar.gz | tar xz
sudo mv cplt /usr/local/bin/

# macOS, Intel
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-x86_64-apple-darwin.tar.gz | tar xz
sudo mv cplt /usr/local/bin/

# Linux, x86_64
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv cplt /usr/local/bin/

# Linux, ARM64
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-aarch64-unknown-linux-gnu.tar.gz | tar xz
sudo mv cplt /usr/local/bin/

Todo binário de release carrega uma atestação de proveniência de build. Verifique-a:```bash gh attestation verify cplt -o navikt

root@kitploit:~
### Compilar a partir do código-fonte```bash
git clone https://github.com/navikt/cplt.git && cd cplt
cargo build --release
sudo cp target/release/cplt /usr/local/bin/

Ou com mise:```bash mise run install

root@kitploit:~
`mise run install` e builds manuais colocam o cplt em `/usr/local/bin/cplt`. Se você também tem o build do Homebrew em `/opt/homebrew/bin/cplt`, coloque `/usr/local/bin` primeiro no `PATH` para que seu build de desenvolvimento tenha prioridade:```bash
# Check which cplt is active
which cplt

# If it shows /opt/homebrew/bin/cplt, reorder your PATH:
export PATH="/usr/local/bin:$PATH"

Ou apenas execute /usr/local/bin/cplt explicitamente e ignore completamente a resolução do PATH.

Windows (WSL2)

O cplt não tem backend de sandbox para Windows. A aplicação é feita via Apple Seatbelt no macOS e Landlock LSM no Linux, portanto não há nada para executar nativamente no Windows. A rota suportada é o WSL2, onde o cplt é uma instalação Linux comum e a sandbox é aplicada pelo kernel. Todos os ramos do kernel da Microsoft compilam com CONFIG_SECURITY_LANDLOCK=y e listam landlock em primeiro lugar em CONFIG_LSM (config-wsl), disponível desde o kernel 5.15.57.1, e a linha de comando padrão do kernel do WSL não define nenhuma substituição lsm=.

No PowerShell, uma vez:```powershell wsl --install # WSL2 + the default distro (now Ubuntu 26.04 LTS), then reboot wsl --install -d Ubuntu-24.04 # ...or pin an older release wsl --update # keep the Microsoft kernel current, see the ABI note below

root@kitploit:~
Tudo abaixo é executado **dentro da distro** (`wsl`, ou o perfil Ubuntu no Windows Terminal), não no PowerShell:```bash
# 1. Node. Copilot CLI requires Node 22+
#    Ubuntu 26.04 ships 22.x, so apt is enough:
sudo apt update && sudo apt install -y nodejs npm
#    Ubuntu 24.04 ships Node 18, too old. Use nvm, fnm, or NodeSource there instead.

# 2. GitHub CLI, and log in. Ubuntu's universe package works but lags
#    (2.45 on 24.04); add GitHub's apt repo if you want a current gh:
#    https://github.com/cli/cli/blob/trunk/docs/install_linux.md
sudo apt install -y gh
gh auth login

# 3. The agent, installed in the distro, never on the Windows side
npm install -g @github/copilot

# 4. cplt, from the apt archive. The default distro is Ubuntu, so this is
#    the same route as on any other Debian derivative.
curl -fsSL https://navikt.github.io/apt/keyring/navikt-archive-keyring.gpg \
  | sudo tee /usr/share/keyrings/navikt-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/navikt-archive-keyring.gpg] https://navikt.github.io/apt stable main" \
  | sudo tee /etc/apt/sources.list.d/navikt.list
sudo apt update && sudo apt install cplt

# 5. Check the result
cplt doctor

Não instale o Copilot CLI no lado do Windows. Com o interop ativado (o padrão), o PATH do Windows é anexado ao da distro, então um npm install -g @github/copilot do lado do Windows aparece dentro da distro como /mnt/c/Users/<user>/AppData/Roaming/npm/copilot. Essa é uma instalação do Windows acessada via interop. Ela não pode ser executada no sandbox do Linux, e o shim do npm executa um node que a distro não terá, a menos que você tenha instalado um lá também. O sintoma costumava ser um erro de extração de runtime não relacionado. O cplt agora nomeia a causa quando resolve um agente sob /mnt/<drive>/ e está sendo executado sob WSL, e cplt doctor o reporta como uma verificação com falha em vez de passar (#188). O WSL é detectado a partir de estado pertencente ao kernel, seja /run/WSL ou o nome do kernel em /proc/sys/kernel/osrelease e /proc/version, não a partir de WSL_DISTRO_NAME, que está ausente sob sudo e em unidades systemd e que qualquer processo pode definir. Em uma máquina Linux comum, /mnt/c é deixado em paz. É um ponto de montagem comum lá.

Essa verificação tem dois limites, ambos deliberados. Ela se baseia no default automount root, então se você o realocou ([automount] root em /etc/wsl.conf), a instalação do lado do Windows não é reconhecida e você obtém a falha antiga, menos útil, com o caminho nela. E desativar o interop impede que o PATH do Windows vaze, mas não desmonta /mnt/c.

Kernel e Landlock ABI. O WSL atual (2.7.x e posterior) traz o Linux 6.18, que fornece Landlock ABI 7 — tudo o que o cplt usa, exceto o direito de connect() de unix-socket, que precisa do ABI 9 (kernel 7.1). Uma instalação ainda na linha de kernel 6.6 obtém o ABI 3: as regras de filesystem são aplicadas, mas as regras de porta TCP (ABI 4), a restrição de ioctl (ABI 5) e o escopo de signal/abstract-socket (ABI 6) não estão disponíveis, e a filtragem de rede recorre ao proxy CONNECT. wsl --update avança você. cplt doctor imprime a versão do kernel e o ABI que encontrou, que é a verificação que importa na sua máquina.

Não desative o Landlock em .wslconfig. Um [wsl2] kernelCommandLine com uma lista lsm= que omite landlock, ou um [wsl2] kernel= personalizado compilado sem CONFIG_SECURITY_LANDLOCK, remove a aplicação do kernel da qual o cplt depende, e cplt doctor reportará o Landlock como indisponível.

Mantenha o projeto no filesystem do Linux. Trabalhe em ~/src/... dentro da distro em vez de /mnt/c/Users/.... A própria orientação da Microsoft é que o acesso a arquivos entre sistemas operacionais é marcadamente mais lento, e /mnt/c é servido via 9p por padrão a partir do WSL 2.9.x (virtiofs é opt-in via [wsl2] virtiofs=true). Mais ao ponto, não verificamos como o Landlock aplica regras nessa montagem. O kernel não documenta nenhuma exclusão para filesystems com suporte de rede ou FUSE, apenas pipes, sockets e nsfs, e a própria suíte de testes do Landlock exercita 9p e FUSE, então esperamos que funcione. Ninguém aqui confirmou isso. Trate um projeto sob /mnt/c como não comprovado em vez de suportado.

Bubblewrap. O Ubuntu 23.10+ bloqueia namespaces de usuário não privilegiados através de kernel.apparmor_restrict_unprivileged_userns, o que quebra o bwrap. Esse sysctl vem de um patch do kernel do Ubuntu que está ausente do kernel da Microsoft, então a camada opcional do Bubblewrap deve funcionar no Ubuntu-sob-WSL2. Isso é inferência a partir do código-fonte do kernel, não algo que executamos. Se o bwrap falhar lá, por favor diga isso em #189. O próprio filtro seccomp do cplt é um programa BPF simples de PR_SET_SECCOMP, que se empilha sobre o filtro que o WSL instala em cada processo.

Ainda não verificado em uma instalação real do WSL2. Verificado a partir do código-fonte: o Landlock está compilado e é o primeiro em CONFIG_LSM no kernel da Microsoft; a detecção de /mnt/<drive>/, os sinais de WSL que ele usa e seu texto de erro; que cplt doctor falha em tal agente e imprime kernel + Landlock ABI; os requisitos de 5.13+/6.7+; e que install.sh instala o binário de release do Linux. Ainda não verificado por ninguém aqui: como o Landlock se comporta em /mnt/c, se o Bubblewrap funciona sob WSL2, as versões exatas de pacotes que sua release de distro fornece, e a sequência acima de ponta a ponta. Se você executá-lo, por favor relate o que realmente aconteceu em #189.

Configuração do shell (recomendado)

Por padrão, você obtém o sandbox digitando cplt. Para fazer o copilot simples também ser executado em sandbox:```bash cplt --shell-install

root@kitploit:~
Isso detecta seu shell, anexa o alias ao seu arquivo rc e imprime o que fez. Execute quantas vezes quiser, ele não adicionará duplicatas.

`--agent` escolhe qual comando recebe o alias, e todo agente que o cplt pode iniciar está disponível:```bash
cplt --shell-install --agent opencode   # 'opencode' runs sandboxed
cplt --shell-install --agent claude     # and 'claude', alongside the others

Cada instalação adiciona ao seu arquivo rc em vez de substituir o que já está lá, então você pode isolar quantos agentes usar. Sem --agent você obtém copilot, que é o que a flag sempre instalou.

ShellArquivo modificadoO que é adicionado (para --agent opencode)
zsh (padrão do macOS)~/.zshrceval "$(cplt --shell-setup --agent opencode)"
bash~/.bashrceval "$(cplt --shell-setup --agent opencode)"
fish~/.config/fish/conf.d/cplt.fishalias opencode 'cplt --agent opencode'

--agent antigravity instala aliases tanto para antigravity quanto para agy, já que qualquer um dos nomes inicia o mesmo agente.

Reinicie seu shell ou dê source no arquivo para ativar.

Não há alias para --agent shell: não existe um binário shell para sobrescrever. Digite cplt --agent shell para um shell isolado, ou cplt exec -- <command> para um único comando.

Configuração manual (alternativa)

Se você preferir não usar --shell-install, adicione a linha você mesmo:```bash

zsh / bash

eval "$(cplt --shell-setup --agent opencode)"

fish

alias opencode 'cplt --agent opencode'

root@kitploit:~
O mesmo padrão que mise, direnv e starship usam.
</details>

**Por que cada alias nomeia seu agente.** `alias opencode=cplt` não faria o que parece. O `cplt` simplesmente escolhe seu agente a partir de `--agent`, depois do arquivo de configuração, e então do que encontrar no PATH — e a detecção do PATH prefere `copilot`. Digitar `opencode` acabaria isolando o Copilot, sem nada na tela para avisar. O alias passa `--agent` para que o comando que você digita seja o agente que você obtém.

**Por que um alias em vez de um symlink?** O cplt e o Copilot CLI instalam no mesmo diretório bin do Homebrew (`/opt/homebrew/bin/`), e apenas um arquivo chamado `copilot` pode existir lá, então um symlink entraria em conflito. Um alias contorna isso. O binário real `copilot` permanece no PATH onde o cplt pode encontrá-lo e envolvê-lo, e o alias redireciona seu comando.

> **Nota:** o cplt se recusa a aninhar. Se ele detectar que já está sendo executado dentro de um sandbox (através da variável de ambiente `__CPLT_WRAPPED`), ele não iniciará novamente. Subcomandos somente leitura, como `--print-profile` e `cplt doctor`, ainda funcionam dentro de um sandbox existente.

## Uso```
cplt [OPTIONS] [-- <AGENT_ARGS>...]

Tudo depois de -- vai direto para o processo do agente (copilot, opencode, gemini, antigravity, pi, claude, goose, dsh ou shell).

Presets de política

Um preset define uma linha de base para os cinco principais toggles de sandbox com uma flag em vez de uma lista delas. Flags individuais ainda prevalecem sobre o preset, então --preset permissive --no-allow-tmp-exec faz o que diz. Também configurável como [sandbox] preset = "..." no config.

Matriz completa de presets e ordem de resolução: docs/configuration.md.

Acesso a arquivos

O diretório do projeto é o workspace gravável, mais uma allowlist estreita necessária para autenticação, runtime e ferramentas (veja a tabela acima). O kernel bloqueia todo o resto, incluindo chaves SSH e credenciais de nuvem.

Variáveis de ambiente

cplt sanitiza o ambiente filho por padrão. Apenas variáveis seguras passam, e credenciais de nuvem, URLs de banco de dados e tokens de pacotes são removidos. Também injeta variáveis de hardening que bloqueiam scripts de ciclo de vida do npm/yarn/pnpm (hooks postinstall, o vetor de ataque de cadeia de suprimentos número um), desabilitam assinatura de commit e tag do git (já que ~/.ssh e ~/.gnupg são inacessíveis dentro do sandbox), e optam por não participar de telemetria de ferramentas de desenvolvimento (DO_NOT_TRACK=1, NEXT_TELEMETRY_DISABLED=1, TURBO_TELEMETRY_DISABLED=1, CHECKPOINT_DISABLE=1, e outros).

O que passa:

Allowlist de prefixo com proteção de sufixo secreto. Uma variável que corresponde a um prefixo permitido como COPILOT_* ou YARN_* ainda é descartada se terminar em um sufixo portador de segredo: _TOKEN, _AUTH, _SECRET, _SECRET_KEY, _KEY, _PASSWORD ou _CREDENTIALS. Então COPILOT_DEBUG passa e COPILOT_API_KEY não.

Sempre bloqueados: AWS_*, AZURE_*, NPM_TOKEN, DATABASE_URL, VAULT_TOKEN, SSH_AUTH_SOCK, variáveis do Docker, tokens de CI, e qualquer coisa que não esteja na allowlist.

FlagO que faz
--pass-env <VAR>Passa uma variável de ambiente para o agente. Repetível
--inherit-env⚠️ Perigoso. Herda o ambiente pai completo. Remove apenas , , , . Apenas para depuração

Toggles de sandbox

Runtimes suportados

cplt auto-descobre ferramentas instaladas e escreve regras de sandbox para corresponder. Geralmente apenas diretórios que existem no disco recebem regras, então não há caminhos fantasma. No macOS, diretórios de aplicativos graváveis são incluídos quando descobertos mesmo se ainda não existirem, para que possam ser criados no primeiro uso. O Linux não pode permitir escrita em um caminho inexistente, então a criação precisa acontecer fora do sandbox lá.

Execute cplt doctor para ver se o cplt funcionará aqui para o seu agente, e cplt doctor --verbose para tudo que ele detectou na sua máquina.

Depuração

Flags de sessão

Estas se traduzem nas próprias flags de sessão do agente, então você não precisa de um separador --.

--continue e --resume também são mapeados para OpenCode, Antigravity e Claude Code:

¹ Nem OpenCode nem Antigravity têm um seletor de sessão interativo, então um --resume sozinho significa "continuar a última sessão". Claude Code tem um, então mapeia diretamente.

--remote e --name são exclusivos do Copilot. Pi e modo shell não recebem tradução alguma, então todas as quatro flags são descartadas para eles. Auto-resume é um mecanismo separado: quando você invoca cplt sem args de pass-through e sem flags de sessão, ele anexa --resume para você, e isso se aplica apenas ao Copilot.

Combine-os com flags de sandbox e args de pass-through --:```bash cplt --resume=my-task # resume by name cplt --remote --name my-task -- -p "fix tests" # remote + named + prompt

root@kitploit:~
### Agentes

Escolha um com `--agent <name>`, ou torne-o o padrão com `cplt config set sandbox.agent <name>`. Copilot, OpenCode e Antigravity são detectados automaticamente a partir do `PATH` nessa ordem quando você não nomeia um.

| Agente | Valor de `--agent` | Detectado automaticamente | Autenticação |
| --- | --- | --- | --- |
| GitHub Copilot CLI | `copilot` | sim, prioridade 1 | Token do GitHub, do Keychain ou do `gh` |
| [OpenCode](https://opencode.ai/) | `opencode` | sim, prioridade 2 | Assinatura do Copilot via `/connect`, ou `--pass-env ANTHROPIC_API_KEY` |
| [Antigravity CLI](https://github.com/google-antigravity/antigravity-cli) | `antigravity`, aliases `agy` e `agi` | sim, prioridade 3 | Google OAuth no navegador |
| [Pi](https://github.com/earendil-works/pi) | `pi` | não | `--pass-env ANTHROPIC_API_KEY` e similares |
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `claude`, aliases `cc` e `claude-code` | não | OAuth de assinatura em `~/.claude` ou no Keychain, `CLAUDE_CODE_OAUTH_TOKEN` (descarta a concessão do Keychain), ou `--pass-env ANTHROPIC_API_KEY` |
| [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | `dsh`, aliases `deepseek` e `deepseek-harness` | não | `--pass-env DEEPSEEK_API_KEY`, ou `$DSH_HOME/.env` (`~/.dsh/.env`) |
| Seu shell | `shell` | não | nenhuma |

- **Pi, Claude Code, goose e DeepSeek Harness nunca são detectados automaticamente.** `pi` e `dsh` são nomes de binários genéricos que podem colidir com outra coisa na sua máquina, e o Claude Code precisa ser escolhido de propósito.
- **Chaves de API de terceiros são opt-in.** `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN` e as variáveis de roteamento Bedrock/Vertex (`CLAUDE_CODE_USE_BEDROCK`, `AWS_BEARER_TOKEN_BEDROCK`, `CLAUDE_CODE_USE_VERTEX`, `ANTHROPIC_VERTEX_PROJECT_ID`, `GOOGLE_CLOUD_PROJECT`) nunca passam, a menos que você as nomeie com `--pass-env`.
- **Autenticação por assinatura não precisa de variável de ambiente.** O fluxo de dispositivo `/connect` do OpenCode armazena seu token em `~/.local/share/opencode/auth.json`, e o token OAuth do Claude Code fica em `~/.claude` (`.credentials.json` no Linux) ou no Keychain do macOS. Ambos são acessíveis dentro do sandbox, então o cplt não fica insistindo sobre uma chave de API ausente para nenhum dos dois.
- **Fluxos OAuth no navegador precisam de `--allow-browser`** quando aparece um prompt de login. Isso cobre o Antigravity; todos os outros agentes aqui usam um fluxo de dispositivo que imprime um código e uma URL e não precisa de navegador. A flag permite que o agente inicie qualquer aplicação fora do sandbox e não pode ser restringida a URLs, então ative-a para o login e desative-a novamente — veja a [tabela de flags](#sandbox-toggles) e [docs/security.md](https://github.com/navikt/cplt/blob/main/docs/security.md#--allow-browser-is-a-sandbox-escape-and-cannot-be-scoped).
- **A atualização automática do Claude Code está desabilitada** com `DISABLE_AUTOUPDATER=1`. O Claude Code não tem uma flag `--no-auto-update`, a auto-atualização dentro do sandbox é um vetor de persistência, e falharia de qualquer forma contra caminhos de instalação somente leitura.
- **`CLAUDE_CONFIG_DIR` é respeitado.** Quando definido, o cplt concede esse diretório em vez de `~/.claude` e repassa a variável, então uma raiz de configuração realocada continua funcionando.
- O OpenCode é [um cliente Copilot oficialmente suportado](https://github.blog/changelog/2026-01-16-github-copilot-now-supports-opencode/), então sua assinatura existente do Copilot funciona com `/connect` dentro do OpenCode.

Diretórios de configuração por agente, uso do Keychain, permissões de execução e isolamento de ambiente estão em [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md#supported-agents).

### Suporte ao goose

O cplt pode colocar em sandbox o [goose](https://github.com/aaif-goose/goose), o agente de IA de código aberto (binário `goose`). Verificado com o goose 1.48.0.```bash
# Run goose (must be explicit — not auto-detected)
cplt --agent goose

# goose is provider-agnostic — pass your provider's API key
cplt --agent goose --pass-env ANTHROPIC_API_KEY
cplt --agent goose --pass-env OPENAI_API_KEY

# Skip the keyring entirely: keep the key in the environment
GOOSE_DISABLE_KEYRING=1 cplt --agent goose --pass-env OPENAI_API_KEY --pass-env GOOSE_DISABLE_KEYRING

# Set goose as your default agent
cplt config set sandbox.agent goose

Notas de segurança para goose:

  • Não é detectado automaticamente: selecione explicitamente com --agent goose ou defina sandbox.agent = "goose" na config
  • Agnóstico em relação ao provedor: o goose encaminha o tráfego do modelo para um provedor configurado pelo usuário (Anthropic, OpenAI, Google, Databricks, OpenRouter, …). Chaves de provedores comuns (ANTHROPIC_API_KEY, OPENAI_API_KEY, AZURE_OPENAI_API_KEY, GOOGLE_API_KEY, DATABRICKS_HOST/DATABRICKS_TOKEN, GROQ_API_KEY, OPENROUTER_API_KEY, XAI_API_KEY, AWS_BEARER_TOKEN_BEDROCK) são reconhecidas como dicas de autenticação e devem ser passadas via --pass-env. O goose lê , não . Qualquer provedor fora desse subconjunto ainda funciona: nomeie sua variável com

Suporte ao DeepSeek Harness

O cplt pode colocar em sandbox o DeepSeek Harness (binário dsh), o harness de agente orientado a plugins da DeepSeek. O upstream o disponibiliza como developer preview e seu próprio SAFETY.md diz para não confiar em seus controles como a única fronteira, que é exatamente o caso para o qual o cplt existe.```bash

Run DSH (must be explicit — not auto-detected)

cplt --agent dsh

Pass the API key, or keep it in $DSH_HOME/.env

cplt --agent dsh --pass-env DEEPSEEK_API_KEY

Set DSH as your default agent

cplt config set sandbox.agent dsh

root@kitploit:~
**Notas de segurança para DSH:**
- **Não é detetado automaticamente**: selecione-o com `--agent dsh` (aliases `deepseek`, `deepseek-harness`) ou defina `sandbox.agent = "dsh"`. `dsh` é um nome de comando curto e genérico que pode pertencer a outra coisa na sua máquina
- **Desative o sandbox do próprio DSH dentro do cplt**: o DSH envolve cada chamada de shell e de ferramenta de ficheiro no seu próprio sandbox de processo — Seatbelt no macOS, bwrap ou Landlock no Linux. Nenhum deles se aninha dentro do cplt. O macOS não suporta chamadas `sandbox-exec` aninhadas (a mesma limitação que faz o cplt desativar o sandbox interno do Gradle, ver [Limitations](#limitations)), e o bwrap constrói o seu namespace com `unshare`, que o filtro seccomp do cplt nega. O cplt é a fronteira de imposição de qualquer forma, por isso escolha o preset de permissões `danger-full-access` fornecido pelo DSH para sessões em sandbox. Deixe o runner interno ativo e as chamadas de ferramentas falham com um erro do sandbox runner em vez de um erro de tarefa
- **Uma raiz home, e o cplt segue a substituição**: o DSH mantém sessões, definições, cache e perfis sob `$DSH_HOME` (`~/.dsh` por predefinição). `DSH_HOME` está na lista de permissões de env, por isso o processo filho resolve a mesma raiz que o cplt concede. Um valor que aponte para uma raiz de sistema ou para o seu diretório home é recusado antes do lançamento, o mesmo veto pelo qual `CLAUDE_CONFIG_DIR` passa
- **Guarda de persistência no host**: `$DSH_HOME/cordis.patch.yml`, o overlay ao nível do home que o Loader lê no arranque, tem escrita negada. `$DSH_HOME/profiles/` permanece gravável porque o DSH reescreve a raiz de inclusão `cordis.yml` de cada perfil a cada arranque, por isso um `cordis.patch.yml` por perfil e plugins instalados são um residual documentado — faça edições de perfil e de `dsh plugin` fora do cplt, e lance sempre `dsh` através do cplt para que qualquer coisa plantada continue a correr em sandbox
- **Domínios predefinidos**: apenas `deepseek.com`. O adaptador `dsh-llm-deepseek` fornecido usa por predefinição `https://api.deepseek.com`. Aponte `DEEPSEEK_BASE_URL` para um gateway e terá de adicionar o domínio desse gateway via `allowed_domains`
- **Autenticação**: passe a chave com `--pass-env DEEPSEEK_API_KEY`, ou mantenha-a em `$DSH_HOME/.env`. Uma chave guardada através da própria UI de modelos do DSH fica em `$DSH_HOME/.credentials.yaml`, dentro da mesma raiz gravável. O Keychain do macOS é negado, por isso `git push` sobre HTTPS precisa do token do `gh` em `hosts.yml` ou de `--pass-env GH_TOKEN`

### Modo shell

Execute uma shell simples em sandbox sem agente de IA e com as mesmas restrições. Útil para testar ferramentas de build, depurar problemas de sandbox, ou simplesmente trabalhar com cuidado à mão.```bash
# Interactive sandboxed shell (uses $SHELL: fish, zsh, bash)
cplt --agent shell

# Inspect what's allowed without entering the shell
cplt --agent shell --print-profile

As mesmas regras de negação por padrão se aplicam: isolamento do sistema de arquivos, restrições de rede, sanitização de env. Os diretórios de configuração do shell (variáveis e histórico do fish, histórico do zsh) permanecem graváveis.

Para um único comando, cplt exec é mais limpo do que cplt --agent shell -- -c 'cmd'.

Modo exec

Execute qualquer comando dentro do sandbox sem iniciar um agente. Sem banner de inicialização, sem prompt de confirmação, portanto é adequado para scripts, pipes e aliases de shell.```bash

Sandbox a single command

cplt exec -- npm install cplt exec -- make build cplt exec -- go test ./...

Compound commands via $SHELL -c

cplt exec -c "npm install && npm test"

Pass sandbox flags as usual

cplt exec --allow-lifecycle-scripts -- npm install cplt exec --project-dir /path/to/repo -- make build cplt exec --with-proxy -- curl https://example.com

Shell aliases for sandboxed tools

alias npm="cplt exec -- npm" alias node="cplt exec -- node" alias python="cplt exec -- python"

root@kitploit:~
Todas as flags de nível superior do `cplt` se aplicam: `--project-dir`, `--allow-read`, `--deny-path`, `--with-proxy`, `--pass-env` e o restante. Adicione `--no-quiet` para ver o resumo completo da configuração do sandbox antes da execução do comando.

### Exemplos```bash
# The common case: Copilot in the sandbox
cplt -- -p "fix the tests"

# Sessions
cplt --resume                                   # pick one interactively
cplt --resume=my-refactor                       # by name
cplt --continue                                 # most recent in this directory
cplt --remote --name my-task -- -p "fix tests"  # named remote session

# Check the environment before the first run
cplt doctor

# Let Copilot read a shared library directory
cplt --allow-read ~/shared-libs -- -p "use shared-libs"

# Block a path you don't want Copilot to see
cplt --deny-path ~/.config/gh -- -p "refactor auth"

# Extra outbound port, e.g. an external API
cplt --allow-port 8443 -- -p "test the API"

# Localhost for MCP servers or dev servers
cplt --allow-localhost 3000 --allow-localhost 8080 -- -p "use the MCP server"

# All of localhost, needed by Next.js/Turbopack and Vite builds
cplt --allow-localhost-any -- -p "fix the build"

# Pass specific env vars through
cplt --pass-env MY_CUSTOM_VAR --pass-env ANOTHER_VAR -- -p "run with custom config"

# Inherit the full environment (dangerous, debugging only)
cplt --inherit-env -- -p "debug the build"

# Network
cplt --no-proxy -- -p "fix the tests"                    # proxy is on by default
cplt --blocked-domains ./blocked-domains.txt -- -p "refactor"
cplt --allow-private-domain intern.nav.no -- -p "use mcp-onboarding"

# Non-interactive / CI (skip the confirmation prompt)
cplt --yes -- -p "fix the tests"

# Inspect and debug the sandbox itself
cplt --print-profile
cplt --show-denials -- -p "fix the tests"

Configuração

A configuração acontece em dois níveis: global, para preferências do desenvolvedor, e por repositório, para políticas da equipe.```bash

Browse and change settings interactively

cplt settings

Set global preferences

cplt config set sandbox.quiet true cplt config set proxy.blocked_domains "~/.config/cplt/blocked-domains.txt" cplt config set git_guard.mode warn # observe pushes instead of blocking them cplt config set gh_guard.enabled false # opt out of the gh guard entirely

Set per-repo policy (committed to .cplt.toml)

cplt config set --repo sandbox.allow_jvm_attach true cplt config set --repo deny.paths "~/secrets"

Inspect

cplt config show # effective config (file + defaults) cplt config explain # every key with its description

root@kitploit:~
`cplt settings` é o editor interativo, com visualizações Effective, Global e Repository, pesquisa, alterações preparadas e uma confirmação explícita antes de guardar qualquer coisa sensível à segurança. `cplt config` mantém-se a interface não interativa estável para scripts e CI. As propostas de repositório continuam a ser submetidas e aprovadas separadamente com `cplt trust`. O editor nunca as submete nem aprova automaticamente.

A precedência segue as flags da CLI, depois o ficheiro de configuração global em `~/.config/cplt/config.toml`, e depois os valores predefinidos incorporados. A configuração por repositório em `.cplt.toml` é uma camada separada em vez de um degrau nessa escada: `[deny]` restringe incondicionalmente, e as permissões aprovadas são apenas aditivas, pelo que um repositório pode ativar uma funcionalidade mas nunca pode desativar algo definido por uma flag da CLI ou pela configuração global.

Um `.cplt.toml` na raiz do repositório contém a política da equipa:```toml
[deny]                    # Applied automatically, no opt-in needed
paths = ["~/secrets", "~/.vault-token"]
env = ["VAULT_TOKEN", "DATABASE_URL"]

[propose]                 # Requires developer approval (cplt trust accept)
gh_guard = true
git_push_prevention = true
allow_jvm_attach = true
allow_docker = true

[propose.allow]
ports = [5432]
localhost = [3000]
socket = ["/var/run/docker.sock"]

O cplt lê-o a partir do git HEAD, pelo que o agente não pode adulterar a sua própria política a meio da sessão, e as aprovações de confiança ficam fixadas ao conteúdo do ficheiro. Um .cplt.toml não commitado não concede nada até ser commitado, embora as suas chaves [deny] continuem a aplicar-se. Em CI e scripts, onde ninguém pode responder a um prompt, --accept-repo-config aprova as propostas do ficheiro commitado para essa única execução sem persistir qualquer confiança. O cplt init escreve um por ti ao detetar as ferramentas do projeto:```bash cplt init # preview detected permissions cplt init --write # write .cplt.toml to disk cplt init --quiet # output only TOML (pipe-friendly) cplt init --global # generate a personal ~/.config/cplt/config.toml

root@kitploit:~
Ele conhece JVM (Gradle/Maven), Node.js, Docker, Python, Rust, Go, Playwright, Spring Boot, Ktor, TestContainers, Next.js, Vite, Flyway, Cypress, e segredos de ambiente a partir de `.env.example`. Permissões perigosas saem do gerador com um aviso de risco anexado. `--global` olha para coisas ao nível da máquina: navegadores Playwright, assinatura GPG, credenciais de registry, agentes alternativos.

Algumas chaves são apenas globais e rejeitadas de `.cplt.toml` porque são específicas da máquina ou uma preferência local: `sandbox.agent`, `sandbox.quiet`, `sandbox.yes`, `sandbox.validate`, `sandbox.scratch_dir`, `sandbox.pass_env`, `sandbox.inherit_env`, `sandbox.allow_cache_exec`, `sandbox.allow_cache_exec_any`, `proxy.enabled`, `proxy.port`, `proxy.log_file`, `proxy.log_level`, `proxy.blocked_domains`, `proxy.allowed_domains`, e todas as chaves `[gh_guard]` e `[git_guard]`.

Detalhes completos, incluindo o modelo de confiança, regras de expansão de caminhos, e a referência completa do ficheiro de configuração: [docs/configuration.md](https://github.com/navikt/cplt/blob/main/docs/configuration.md).

## Arquitetura```
┌──────────────────────────────────┐
│  cplt (Rust binary)              │
│  ┌───────────┐  ┌─────────────┐  │
│  │ Policy    │  │ CONNECT     │  │
│  │ Generator │  │ Proxy       │  │
│  └─────┬─────┘  │ (optional)  │  │
│        │        └─────────────┘  │
│        ▼                         │
│  ┌─────────────┬────────────┐    │
│  │   macOS     │   Linux    │    │
│  │  Seatbelt   │  Landlock  │    │
│  │  sandbox-   │  + seccomp │    │
│  │  exec       │  pre_exec  │    │
│  └─────────────┴────────────┘    │
│        │                         │
│        ▼                         │
│  copilot (sandboxed)             │
│  ├── All child processes         │
│  ├── Cannot read ~/.ssh          │
│  ├── Network port-restricted     │
│  ├── SSH agent blocked           │
│  └── Filesystem = primary ctrl   │
└──────────────────────────────────┘

O modelo de segurança é um sistema de arquivos deny-by-default com imposição pelo kernel. No macOS, e no Linux com kernel 6.7+ (Landlock ABI v4), a rede é restrita à porta 443 por padrão, com --allow-port para extras. Em kernels Linux mais antigos, o proxy CONNECT fornece essa restrição, razão pela qual está habilitado por padrão. O acesso ao agente SSH e a saída para localhost são bloqueados no kernel no macOS. No Linux, nenhum dos dois é: regras Landlock baseadas em porta não conseguem distinguir localhost de um host remoto, e o connect() de socket unix não é controlado pelo Landlock abaixo do kernel 7.1, então, além dos sockets que o bubblewrap mascara, o SSH_AUTH_SOCK retido é a única coisa entre o agente e suas chaves carregadas. O gerador de perfil descobre seu ambiente (cplt doctor --verbose mostra os mesmos resultados de sondagem) e emite regras apenas para diretórios de ferramentas que realmente existem no disco. Menos regras, sandbox mais restrita.

  • macOS: um perfil Seatbelt/SBPL é gerado e entregue ao sandbox-exec
  • Linux: regras Landlock LSM mais um filtro seccomp-BPF, aplicados via pre_exec (kernel 5.13+, filtragem de porta TCP no 6.7+)

Internos e layout de módulos: docs/architecture.md. Modelo de ameaças, camadas de defesa e lacunas honestas: SECURITY.md.

Segurança

Um binário, dependências mínimas, sem serviços em tempo de execução, sem telemetria. Três camadas de defesa, com limites claros entre elas:

Contra o que o cplt protege:

  • Exfiltração de segredos (chaves SSH, credenciais de nuvem, arquivos .env): bloqueado pelo kernel
  • Execução não autorizada de código a partir de diretórios temporários: bloqueado pelo kernel
  • Persistência via binários em diretórios de cache: bloqueado pelo kernel, já que esses diretórios têm exec negado
  • Persistência via git hooks no projeto: .git/hooks tem escrita negada no kernel no macOS. No Linux, com Landlock e sem Bubblewrap, permanece gravável, e o próprio git do lado pai do cplt então é executado com core.hooksPath=/dev/null, de modo que nunca executa um hook plantado, embora um git que você mesmo execute ainda o fará
  • Persistência via diretórios de ferramentas de gerenciadores de pacotes que são simultaneamente graváveis e executáveis (shims do mise, PNPM_HOME, ~/.deno/bin, ~/.bun/bin): a escrita é concedida ali para que pnpm add -g e similares funcionem dentro da sandbox, então um agente pode deixar um binário para trás que um shell posterior pegará do seu PATH
  • Um binário plantado sequestrando o agente que o cplt lança: no lançamento e na auditoria, o cplt resolve os auxiliares que ele mesmo executa (, , , , e o do qual lê um token) a partir de diretórios fixos do sistema em vez do , mas o próprio binário do agente é executado de onde quer que tenha sido descoberto, o que, para uma instalação npm-global, geralmente fica sob uma árvore mise ou node gravável. O cplt não consegue resolvê-lo a partir de um diretório fixo — ele legitimamente vive onde seu gerenciador de versões o colocou — então verifica o caminho resolvido contra as regras de escrita que a sandbox está prestes a aplicar e , nomeando o binário e a árvore gravável, e então prossegue

Contra o que o cplt não protege:

  • Código malicioso já presente no diretório do projeto. O agente tem leitura/escrita total ali
  • Bugs de lógica que o agente introduz. Você ainda revisa o código
  • Um adversário sofisticado contornando a guarda de comandos. Use proteção de branch no lado do servidor
  • Ataques de rede em domínios permitidos. Se github.com é permitido, o agente pode ler e escrever ali
  • Acesso ao Keychain do macOS, para agentes que armazenam autenticação ali. Os conteúdos são protegidos por senha, e sandbox.keychain_substitute pode trocar a concessão onde um agente tem outra credencial

Nossas prioridades, em ordem: correto (toda afirmação é testada, todo caso extremo tem uma CVE ou referência de pesquisa), transparente (SECURITY.md não esconde nada), simples (um binário, zero configuração necessária, padrões sensatos) e útil (sair do caminho e deixar o agente trabalhar, com segurança).

Mais: docs/security.md · SECURITY.md

Rede e proxy

O proxy está ativado por padrão. Todo o tráfego de saída do Copilot CLI, gh e curl passa por um proxy CONNECT localhost via HTTP_PROXY/HTTPS_PROXY e NODE_USE_ENV_PROXY=1. Ele escuta em uma porta efêmera atribuída pelo SO, então nada colide. Você obtém registro de conexões em tempo real, bloqueio de domínios, lista de permissões de domínios, um log de auditoria persistente e a mesma política de portas que a sandbox impõe (443 mais qualquer coisa em allow.ports).```bash cplt --proxy-forced -- -p "fix tests" # force all egress through the proxy cplt --no-proxy -- -p "fix tests" # disable for one run cplt --blocked-domains blocked-domains.txt -- -p "x" # block known-bad domains cplt --allowed-domains allowed-domains.txt -- -p "x" # allowlist mode cplt --default-allowlist -- -p "x" # fail-closed: only the agent's own domains cplt --observe-domains -- -p "x" # record what the agent contacts, block nothing cplt --proxy-upstream http://proxy.corp:8080 -- -p "x" # chain through a corporate proxy

root@kitploit:~
`--observe-domains-out <FILE>` grava o conjunto observado, um domínio por linha, e
`--proxy-upstream-no-proxy <HOST>` lista os hosts a serem acessados diretamente em vez de através
do upstream.```bash
cplt config set proxy.enabled false
cplt config set proxy.blocked_domains "~/.config/cplt/blocked-domains.txt"
cplt config set proxy.allowed_domains "~/.config/cplt/allowed-domains.txt"
cplt config set proxy.log_file "~/.config/cplt/proxy.log"

O modo forçado por proxy é opt-in. Ele restringe a saída do kernel à porta do proxy, de modo que um socket aberto diretamente, ou um env -u HTTPS_PROXY, não consiga escapar. A aplicação é total no macOS, que fixa em localhost:<proxy_port>. No Linux, bloqueia TCP direto para :443, e uma regra seccomp permite apenas SOCK_STREAM com protocolo 0 ou IPPROTO_TCP para AF_INET/AF_INET6, portanto UDP, raw, SCTP e DCCP também ficam fechados — ao custo de qualquer coisa que abra tal socket, não apenas código que envia UDP. O que resta é um resíduo baseado em porta, evil.com:<proxy_port>, até #114.

Fora do modo forçado por proxy, o Linux não restringe UDP. Os direitos de rede do Landlock são apenas TCP até a ABI v10, o cplt trata apenas AccessNet::ConnectTcp, e a regra seccomp acima é deliberadamente não aplicada — negar SOCK_DGRAM ali quebraria getaddrinfo(3), e portanto todo o DNS, para toda ferramenta não-proxied. UDP de saída para qualquer host, bind UDP de entrada, tunelamento DNS e QUIC/HTTP-3 ficam, portanto, sem mediação no modo padrão, e o proxy CONNECT transporta apenas TCP, então nada disso aparece no log do proxy. O macOS restringe UDP no modo padrão, mas também não o roteia: remote ip "*:443" cobre UDP, então QUIC/HTTP-3 na 443 sai sem tocar no proxy lá também. Sob proxy.forced, o log do proxy é um registro completo da saída no macOS. No Linux, é completo exceto pelo resíduo evil.com:<proxy_port> acima, que não atravessa o proxy e portanto não aparece em seu log.

Ambas as listas correspondem da mesma forma: example.com cobre o domínio exato e todos os subdomínios, a correspondência não diferencia maiúsculas de minúsculas, e pontos finais são removidos. Os arquivos de blocklist e allowlist são relidos a cada cinco segundos, então você pode editá-los ao vivo. O tráfego de localhost contorna o proxy via NO_PROXY e nunca aparece no log de auditoria. --proxy-timeout <SECONDS> limita a leitura de requisições e cabeçalhos (padrão 60) e não derruba túneis CONNECT estabelecidos, que podem ficar ociosos por até uma hora.

Cada flag de proxy, detalhe de filtragem de domínio, encadeamento de proxy corporativo upstream, e o formato do log de conexões: docs/proxy.md.

Guardas de comando

Habilite-as e o cplt intercepta gh e git através de scripts wrapper no $PATH:

Esta é a Camada 3, uma barreira suave. Ela impede que um agente complacente faça algo destrutivo por acidente. Para um limite rígido, apoie-se no sandbox do kernel e na proteção de branch do lado do servidor.

Com a guarda do gh ativada, o cplt também armazena em cache o token do GitHub na inicialização e o serve uma vez através do callback gh auth token, depois exclui o cache. Isso reduz vazamentos acidentais e baseados em ambiente. Não é um limite contra um agente hostil, porque o cache vive no próprio TMPDIR do agente e um agente que o leia antes do consumidor legítimo ainda obtém o token. SECURITY.md tem a declaração completa sobre block_auth_token.

Comportamento completo: docs/gh-guard.md · docs/git-guard.md

Impactos conhecidos

O sandbox bloqueia alguns fluxos de trabalho de propósito. Os mais comuns e suas correções:

O Playwright Chromium precisa de cplt config set sandbox.allow_cache_exec ms-playwright, e o Chromium deve rodar sem seu próprio sandbox aninhado. No macOS, seus helpers não conseguem inicializar um segundo sandbox Seatbelt dentro do cplt (forbidden-sandbox-reinit); no Linux, o filtro seccomp do cplt bloqueia as syscalls de namespace que o sandbox precisa. O Playwright como biblioteca já inicia com --no-sandbox, e esse mesmo opt-in define PLAYWRIGHT_MCP_SANDBOX=false para o Playwright MCP, que de outra forma o reativaria. Qualquer outro lançador de Chromium precisa de --no-sandbox por conta própria. O cplt continua sendo o limite de kernel aplicador, mas um renderer comprometido então recebe o perfil completo do Playwright do cplt em vez do perfil filho mais restrito do Chromium. Veja Cache exec e SECURITY.md.

O commit do Git funciona para todo agente; se o git push funciona via HTTPS depende do agente. Três pré-requisitos: use remotes HTTPS em vez de SSH (git remote set-url origin https://github.com/org/repo.git, ou reescreva globalmente com git config --global url."https://github.com/".insteadOf "[email protected]:"), execute gh auth login uma vez fora do sandbox, e execute gh auth setup-git se o credential helper ainda não estiver configurado. O push então executa gh auth git-credential, que precisa de um token que o gh consiga alcançar de dentro do sandbox — isso difere por agente, veja Git workflow. Pushes para o branch padrão e todos os force pushes são recusados pela guarda do git por padrão; faça push de um feature branch. O agent socket do SSH é bloqueado porque ele desbloqueia todas as chaves carregadas e pode autenticar em qualquer host, enquanto o credential helper do gh é restrito ao GitHub.

A JVM é proxy-aware, então um repositório Maven interno em um IP privado agora precisa ser permitido. O cplt injeta http(s).proxyHost/proxyPort em JAVA_TOOL_OPTIONS, então a resolução de dependências do Gradle e Maven passa pelo proxy CONNECT e aparece no log do proxy em vez de contorná-lo. A guarda SSRF do proxy então recusa um Nexus ou Artifactory interno que resolva para espaço de endereço privado, exatamente como já faz para curl, npm e pip. Adicione seu nome DNS a proxy.allow_private_domains. Uma URL de repositório escrita como IP literal puro (https://10.20.30.40/repository/maven-public/) não pode ser permitida por nenhuma chave — essa verificação roda antes da allow list ser consultada — então tal repositório precisa de um nome DNS. Forks de plugin WorkerExecutor, e um daemon Gradle iniciado fora do cplt e reutilizado dentro, não são proxied. Veja Internal Maven/Gradle repositories on private IPs.

O Gradle 9+ executa seu próprio sandbox aninhado, e o cplt o desativa. Desde o Gradle 8.8 o daemon se envolve em sandbox-exec (controlado por GRADLE_MACOS_SANDBOX, anteriormente a propriedade org.gradle.daemon.sandbox). O macOS não suporta chamadas sandbox-exec aninhadas, então o sandbox interno falha com "Operation not permitted" em operações de socket. O cplt injeta GRADLE_MACOS_SANDBOX=off, já que ele próprio fornece sandboxing em nível de kernel. Este é um problema upstream conhecido que afeta qualquer ferramenta que envolva o Gradle em um sandbox externo. Sobrescreva com --pass-env GRADLE_MACOS_SANDBOX se você realmente quiser o sandbox próprio do Gradle.

O Copilot CLI 1.0.83 executa seu próprio sandbox aninhado, e o cplt o desativa. No Linux, esse sandbox constrói um network namespace — slirp4netns, iptables, /dev/net/tun — e o filtro seccomp do cplt nega o unshare que ele usa. O cplt também define HTTP_PROXY/HTTPS_PROXY, o que na 1.0.83 coloca um sandbox Linux no caminho de saída do proxy, quer você tenha pedido ou não, então os dois colidem em toda inicialização. Sintoma: [cplt] Starting Copilot in sandbox... e depois nada. O cplt injeta o próprio opt-out do Copilot, COPILOT_CLI_SANDBOX_SUPPORT_OVERRIDE=unsupported; o Copilot se retira para a sessão, avisa isso, e deixa seu sandbox.enabled salvo intacto. O cplt é o limite, como é para Gradle e Chromium. Sobrescreva com --pass-env COPILOT_CLI_SANDBOX_SUPPORT_OVERRIDE. Uma política gerenciada empresarial que exija o sandbox sobrescreve tudo isso — veja Copilot CLI's own command sandbox.

Cada impacto, com as tabelas por ferramenta, notas sobre daemon JVM e Kotlin, solução de problemas de GPG, e as diferenças de plataforma de registro privado: docs/known-impacts.md.

Limitações

macOS

  • sandbox-exec está obsoleto. A Apple não o removeu, mas pode removê-lo em uma versão futura do macOS.
  • SBPL não tem filtragem baseada em domínio. O proxy CONNECT opcional fornece bloqueio de domínio em vez disso.
  • O lsopen do SBPL também não tem filtro, então --allow-browser é todo o Launch Services ou nada dele. Com ele ativado, o agente pode lançar qualquer aplicação fora do sandbox, e nenhum wrapper pode restringir isso — veja docs/security.md.

Linux

  • Kernel 5.13+ necessário, com Landlock LSM habilitado.
  • A filtragem de porta TCP precisa do kernel 6.7+. Kernels mais antigos recebem apenas aplicação de filesystem.
  • O Landlock não pode negar subcaminhos dentro de caminhos permitidos, então leitura/escrita/exclusão de .env dentro do diretório do projeto não é aplicada pelo kernel. Escritas em .git/hooks são bloqueadas quando o Bubblewrap está ativo.
  • --deny-path requer Bubblewrap. É aplicado através de máscaras de mount quando o bwrap está ativo. Sem ele, o Landlock é apenas allowlist e o cplt avisa sobre o deny em vez de aplicá-lo.

Mais: docs/security.md

Contribuindo

Contribuições são bem-vindas.```bash git clone https://github.com/navikt/cplt.git && cd cplt git config core.hooksPath hack # enables pre-commit fmt + clippy checks mise run check # runs fmt, clippy, and tests

root@kitploit:~
Abra uma issue antes de iniciar uma grande alteração. Todo PR precisa passar pelo CI (fmt, clippy, testes).

## Referências

- [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md), o modelo de segurança completo, análise de ameaças, estratégia de testes e trabalhos anteriores
- [Apple sandbox-exec(1)](https://keith.github.io/xcode-man-pages/sandbox-exec.1.html)
- [Chromium Seatbelt V2 Design](https://chromium.googlesource.com/chromium/src/sandbox/+show/refs/heads/main/mac/seatbelt_sandbox_design.md)
- [Documentação do Landlock LSM](https://docs.kernel.org/userspace-api/landlock.html)
- [Documentação do seccomp-BPF](https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html)
- [OWASP SSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html)
- [michaelneale/agent-seatbelt-sandbox](https://github.com/michaelneale/agent-seatbelt-sandbox)

## Licença

[MIT](https://github.com/navikt/cplt/blob/main/LICENSE)
Baixar ferramenta
FlagO que faz
--preset strictBloqueio total de rede. Todos os cinco toggles desligados, mais gh_guard, git_guard, proxy.forced (egress via proxy forçado) e proxy.default_allowlist (allowlist de domínios fail-closed) ligados. Válvula de escape: --allow-all-domains desabilita apenas a allowlist
--preset standardOs padrões atuais. Todos os cinco desligados, o diretório scratch permanece ligado. O mesmo que não passar preset
--preset permissiveLiga allow_localhost_any, allow_tmp_exec e allow_lifecycle_scripts
--preset full-trust⚠️ Perigoso. Liga todos os cinco, adicionando allow_env_files e allow_docker
FlagO que faz
-d, --project-dir <DIR>Em qual diretório o Copilot pode trabalhar. Padrão é a raiz do repositório git atual
--allow-read <PATH>Permite ao Copilot ler arquivos fora do projeto, somente leitura. Repetível
--allow-write <PATH>Permite ao Copilot ler e escrever fora do projeto. Use com cuidado. Repetível. A árvore é gravável mas não executável — uma árvore que é ambas é um caminho de drop de binários, então um allow.write sobre ~/.cargo também impede ~/.cargo/bin de executar. Use --allow-exec em uma árvore separada e não sobreposta quando precisar de ambos
--allow-exec <PATH>⚠️ Perigoso. Permite ao agente executar binários de uma árvore fora dos diretórios de ferramentas padrão — um Homebrew ou prefixo de toolchain realocado, por exemplo. Concede leitura e execução, nunca escrita. Repetível. Recusado para uma raiz insegura (/, /tmp, $HOME e seus pais, os diretórios de sistema da plataforma) e para qualquer árvore que se sobreponha a uma gravável — o diretório do projeto, uma concessão --allow-write, um diretório de ferramentas gravável como ~/.cache, um diretório de dados de agente gravável (~/.claude, ~/.local/share/opencode, ~/.pi/agent e similares), o .git real de um worktree ou repo bare, ou uma árvore que os backends tornam gravável sem nenhuma concessão (/tmp e /dev/shm no Linux; /private/tmp e /private/var/folders no macOS): gravável mais executável é um caminho de drop de binários, e nenhum backend consegue subtrair a concessão de escrita da concessão de execução
--allow-socket <PATH>⚠️ Perigoso. Permite um caminho de socket de domínio Unix, por exemplo um daemon LSP customizado ou um socket de banco de dados. Repetível. O que estiver do outro lado roda fora do sandbox, então apontar isso para docker.sock ou um socket de agente é equivalente a --allow-docker, e a única proteção é que sobreposições com --deny-path são rejeitadas. No Linux não faz nada abaixo do kernel 7.1, já que conexões de socket unix não são controladas pelo Landlock antes do ABI v9 (veja Limitações do Linux)
--deny-path <PATH>Bloqueia um caminho que de outra forma seria permitido. Deny sempre vence. Repetível
--allow-port <PORT>Permite tráfego de saída em uma porta extra. Apenas 443 por padrão. Repetível. No macOS a regra é (remote ip "*:PORT"), que é agnóstica de família e portanto carrega UDP além de TCP; o Landlock controla apenas conexões TCP. Sob proxy.forced a porta não abre nenhum socket direto — é alcançável através do proxy, então ferramentas cientes de proxy continuam funcionando
--allow-localhost <PORT>Permite saída para localhost em uma porta. Localhost é bloqueado por padrão. Use para servidores MCP ou servidores de desenvolvimento. Repetível
--allow-localhost-anyPermite saída para localhost em todas as portas. Necessário para ferramentas de build como Turbopack (Next.js) e Vite que usam portas efêmeras aleatórias para IPC
CategoriaExemplosComo
Sistema centralHOME, USER, PATH, SHELL, TMPDIR, LANGAllowlist explícita
TerminalTERM, COLORTERM, TERM_PROGRAMAllowlist explícita
EditorEDITOR, VISUAL, PAGERAllowlist explícita
Tokens de autenticaçãoGH_TOKEN, GITHUB_TOKEN, COPILOT_GITHUB_TOKENPassados apenas se você já os definiu. O gh guard usa um arquivo de uso único em vez disso
Config do CopilotCOPILOT_DEBUG, COPILOT_*Allowlist de prefixo
Runtimes de linguagemNODE_*, GOPATH, CARGO_HOME, JAVA_HOME, VIRTUAL_ENV, PYTHONPATHAllowlist explícita
Gerenciadores de ferramentasNVM_*, FNM_*, PYENV_*, MISE_*, SDKMAN_*, COREPACK_*, YARN_*Allowlist de prefixo
OpenTelemetryOTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTES, OTEL_*Allowlist de prefixo (OTEL_EXPORTER_OTLP_HEADERS pode carregar autenticação opt-in)
Diretórios XDGXDG_CONFIG_HOME, XDG_DATA_HOME, XDG_STATE_HOME, XDG_CACHE_HOMEAllowlist explícita
NO_COLOR
FORCE_COLOR
SSH_AUTH_SOCK
SSH_AGENT_PID
FlagO que faz
--allow-lifecycle-scriptsPermite que scripts de ciclo de vida do npm/yarn/pnpm (hooks postinstall) executem. Bloqueado por padrão. Use quando npm install precisar deles
--allow-gpg-signingPermite assinatura de commit e tag GPG dentro do sandbox. Concede acesso somente leitura ao chaveiro público e ao socket do agente GPG. Chaves privadas permanecem negadas. Veja Assinatura GPG
--allow-jvm-attachPermite sockets unix da JVM Attach API em /tmp. Necessário para MockK inline mocking, agentes inline do Mockito, ByteBuddy. Veja JVM Attach API
--allow-msbuildPermite sockets unix de worker-node do MSBuild em /tmp. Necessário para dotnet build. Não habilita o MSBuild Server persistente. Veja IPC de worker-node do MSBuild
--no-scratch-dirDesabilita o diretório scratch por sessão, que é ligado por padrão. TMPDIR não será redirecionado
--scratch-dirHabilita explicitamente o diretório scratch por sessão. Já é o padrão, então isso serve para sobrescrever scratch_dir = false no config
--brief🧪 Experimental. Escreve o brief de sandbox voltado ao agente no diretório scratch (CPLT_BRIEF.md). Desligado por padrão. Também sandbox.brief = true no config. Instável, então pode mudar ou ser removido em uma versão futura
--no-briefDesliga o brief de sandbox para esta execução, sobrescrevendo sandbox.brief = true no config. Também suprime o bloco AGENTS.md, que é condicionado ao brief
--agents-md🧪 Experimental. Com --brief, também escreve o bloco gerenciado do cplt no AGENTS.md do projeto. Desligado por padrão. Também sandbox.agents_md = true no config. Sem efeito sem --brief. Instável, então pode mudar ou ser removido em uma versão futura
--no-agents-mdDesliga o bloco AGENTS.md para esta execução, sobrescrevendo sandbox.agents_md = true no config. Deixa o brief do diretório scratch intacto
--allow-tmp-exec⚠️ Perigoso. Permite execução a partir de diretórios temporários do sistema (/private/tmp, /private/var/folders). Prefira o diretório scratch
--allow-cache-exec <SUBDIR>Permite execução a partir de um ~/Library/Caches/<SUBDIR>. Repetível. Para ferramentas que armazenam binários compilados ali, como Playwright e pnpm dlx
--allow-cache-exec-any⚠️ Perigoso. Permite execução a partir de todo o ~/Library/Caches. Prefira --allow-cache-exec <SUBDIR>
--allow-browser⚠️ Perigoso. Com isso ligado, o agente pode iniciar qualquer aplicação na sua máquina fora do sandbox. A concessão é o Launch Services, não um navegador: o launchd inicia o alvo fora do perfil Seatbelt, então open -a Terminal /tmp/x.sh roda sem sandbox. Isso não pode ser restrito a URLs — o lsopen do SBPL não aceita filtro, e a concessão é alcançável através de LSOpenCFURLRef() sem o binário open de forma alguma, então nenhum wrapper pode restringi-la (#251, e docs/security.md). Só ligue enquanto um prompt de login estiver realmente na tela (OAuth de servidor MCP, re-autenticação), depois desligue novamente. Desligado por padrão
--deny-clipboardBloqueia o agente de ler ou escrever a área de transferência do macOS (pbpaste/pbcopy) negando o serviço Mach com.apple.pasteboard. Todos os outros serviços Mach (Keychain, DNS, Security framework) não são afetados. Ligado por padrão — esta flag reafirma o padrão
--allow-clipboardDevolve ao agente a área de transferência do macOS, que o cplt nega por padrão. Equivalente a sandbox.deny_clipboard = false
--use-bubblewrapApenas Linux. Exige a camada de namespace do bubblewrap (namespaces PID, mount, IPC, UTS, cgroup, user mais um /tmp privado) sobre o Landlock e seccomp. Erra se bwrap estiver ausente. Auto-detectado quando nenhuma das flags é fornecida
--no-bubblewrapApenas Linux. Nunca usa bubblewrap, mesmo quando instalado. Recorre ao Landlock e seccomp. Use quando o bwrap quebra uma ferramenta específica
RuntimeDiretórios homeVariáveis de ambiente / prefixosDescoberta
Node.js.nvm, .local/share/fnm, .local/binNODE_*, NPM_*, NVM_*, FNM_*node
Rust.cargo, .rustupCARGO_HOME, RUSTUP_HOMEcargo
Gogo/bin, go/pkgGOPATH, GOROOT, GOCACHE, etc.go
Java/Kotlin (JVM).sdkman, .jenv, .gradle, .m2JAVA_HOME, JAVA_TOOL_OPTIONS, GRADLE_*, MAVEN_*, SDKMAN_*, JENV_*java, gradle
Kotlin Native.konannenhumnenhum
Python.pyenvVIRTUAL_ENV, PYTHONPATH, PYENV_ROOT, PYENV_*python3
Yarn Berry.yarnYARN_* (hardening sobrescreve YARN_ENABLE_SCRIPTS)yarn
pnpmLibrary/pnpm, .local/share/pnpmPNPM_HOMEpnpm
CorepacknenhumCOREPACK_*nenhum
mise.local/share/mise, .miseMISE_*mise
FlagO que faz
--doctorObsoleto. Use o subcomando cplt doctor em vez disso
--print-profileImprime o perfil de sandbox gerado (SBPL) e sai
--show-denialsTransmite logs de negação do sandbox do macOS em tempo real
--no-validatePula a verificação de inicialização que confirma que as restrições de sandbox estão ativas
-y, --yesPula o prompt de confirmação interativo. O resumo da configuração ainda é impresso, para auditabilidade. Necessário quando stdin não é um TTY, então CI e scripts precisam dele
-q, --quietSuprime o banner de inicialização e mensagens não essenciais. Erros e avisos ainda são impressos. Também sandbox.quiet = true no config
--no-quietSobrescreve sandbox.quiet = true e mostra o resumo de inicialização de qualquer forma
--no-auditPula o relatório de mudanças pós-sessão. cplt normalmente compara a árvore de trabalho com um commit de linha de base fixado antes da execução e lista o que a sessão tocou, sinalizando caminhos sensíveis. -q também o suprime
--init-configCria um arquivo de config inicial em ~/.config/cplt/config.toml e sai
FlagO que faz
--resume[=SESSION]Retoma uma sessão anterior. --resume sozinho escolhe interativamente, --resume=NAME escolhe por nome ou ID
--continueRetoma a sessão mais recente no diretório atual
--remoteHabilita controle remoto, para que você possa monitorar e conduzir a sessão do GitHub.com ou mobile
--name SESSIONNomeia a sessão para que --resume=NAME possa encontrá-la depois
Flag cpltCopilotOpenCodeAntigravity (agy)Claude Code
--continue--continue--continue--continue--continue
--resume--resume--continue¹--continue¹--resume
--resume=ID--resume=ID--session ID--conversation ID--resume ID
--remote--remoteignoradoignoradoignorado
--name NAME--name NAMEignoradoignoradoignorado
GOOGLE_API_KEY
GEMINI_API_KEY
--pass-env
  • Sem domínios padrão: o goose não contatou nenhum host próprio em uma captura com --observe-domains, então sua allowlist embutida é apenas a base compartilhada de registros de pacotes. Adicione o domínio do seu provedor via allowed_domains antes de habilitar --default-allowlist
  • O Keychain é concedido, e você pode evitá-lo: o goose armazena segredos de provedores no Keychain de login do macOS por padrão, então o cplt o concede — mas essa concessão é mais ampla que a própria entrada do goose (#242). GOOSE_DISABLE_KEYRING=1 faz o goose usar um secrets.yaml em seu diretório de config, e passar a chave com --pass-env evita segredos armazenados por completo. No Linux o goose usa o D-Bus Secret Service, que a concessão do Keychain não afeta
  • O diretório de config é somente leitura: ~/.config/goose/config.yaml declara entradas extensions: cujo cmd o goose executa a cada início de sessão, então um diretório de config gravável é um vetor de persistência no host. Sessões normais não o gravam; mudanças de /mode e permissões de ferramentas persistidas não sobrevivem a uma execução em sandbox. Reconfigure com goose configure fora do cplt
  • Os diretórios de dados (~/.local/share/goose/) e de estado (~/.local/state/goose/) do goose são graváveis, com exec negado. O goose usa esses caminhos XDG no macOS também, e honra as sobrescritas XDG_* lá
  • --continue e --resume sem argumento mapeiam para goose session --resume; --resume=ID para goose session --resume --session-id ID; --name X para goose session --name X. Essas são flags de subcomando, então o cplt injeta o subcomando session com elas. --remote é ignorado (sem equivalente no goose)
  • CamadaImposiçãoContornável?O que protege
    1. Sandbox do kernelmacOS Seatbelt / Linux Landlock+seccomp❌ NãoAcesso a arquivos, exec, portas de rede
    2. Proxy de redeProxy CONNECT, filtragem de domínio❌ Não (dentro da sandbox)Conexões de saída, exfiltração
    3. Guarda de comandosScripts wrapper baseados em PATH⚠️ Barreira suavePushes, merges, releases, escritas de API
    git
    bwrap
    sandbox-exec
    mise
    gh
    PATH
    avisa no lançamento
  • cplt doctor: suas sondagens --version executam cada binário de agente que encontra no seu PATH, no processo pai, então um binário plantado é executado ali — a mesma exposição de caminho descoberto do lançamento acima, razão pela qual o doctor é um relatório e não um limite. Sua verificação de gh é resolvida a partir dos diretórios confiáveis e sua leitura da versão do kernel não gera nenhum processo
  • Exfiltração de dados para domínios não autorizados: bloqueado pelo proxy
  • Pushes acidentais para main e merges de PR sem revisão: bloqueado pela guarda
  • ComandoAção
    gh pr merge, gh repo delete, gh release create🔒 Bloqueado
    git push origin main, git push --force🔒 Bloqueado
    gh api (escrita em outros repositórios)🔒 Verificado por escopo
    gh pr list, gh issue list, git commit✅ Permitido
    git push origin feature-branch✅ Permitido com protect_default_branch_only
    ImpactoCorreção
    Arquivos .env bloqueadoscplt config set sandbox.allow_env_files true
    Hooks de postinstall do npm bloqueadoscplt config set sandbox.allow_lifecycle_scripts true
    go test / mise run bloqueados (execução temporária)O diretório scratch está ativado por padrão. Se você ainda precisar, cplt config set sandbox.allow_tmp_exec true
    Conexões de localhost bloqueadascplt config set allow.localhost 3000, ou cplt config set sandbox.allow_localhost_any true
    Docker bloqueadocplt config set sandbox.allow_docker true ⚠️
    SSH bloqueadoUse remotes HTTPS em vez disso
    Assinatura GPG desabilitadacplt config set sandbox.allow_gpg_signing true
    JVM MockK/Mockito falhacplt config set sandbox.allow_jvm_attach true
    Nós worker do MSBuild do dotnet build bloqueadoscplt config set sandbox.allow_msbuild true
    Credenciais de registro privado bloqueadascplt config set allow.read "~/.m2/settings.xml"
    Repositório Maven/Nexus interno inacessível (Gradle/Maven)cplt config set proxy.allow_private_domains "intern.example.com". Uma URL de repositório com IP literal não pode ser permitida — dê um nome DNS ao host; veja abaixo
    Playwright Chromium não iniciaPermita a execução do cache, depois desabilite o sandbox aninhado do Chromium; veja abaixo