Proteção da Cadeia de Fornecimento
Um agente de programação autónomo instala pacotes constantemente — a estruturação de um projeto puxa centenas de dependências sem que um humano alguma vez leia um nome, quanto mais um registo de alterações. Isso torna o registo de pacotes o canal mais amplo para a entrada de código hostil no sandbox: um nome typosquatted, um lançamento recém-comprometido ou um script postinstall malicioso é executado com todas as permissões do agente no instante em que npm install termina. O Bromure Agentic Coding trata cada obtenção de pacote como entrada não fiável e aplica-lhe uma política por espaço de trabalho no anfitrião, antes de um único byte chegar à VM.
Este capítulo explica o que é intercetado, cada verificação do pipeline, o que acontece quando uma verificação dispara e como ler os resultados no Registo de Segurança. A referência de definições campo a campo para o painel encontra-se em definições da Cadeia de fornecimento.
Porque é que as instalações de pacotes são a superfície de ataque
O sandbox já contém o agente: não pode tocar no seu Mac, e as suas credenciais são engodos (ver Credenciais). O que o sandbox não consegue fazer por si só é avaliar a proveniência do código que o agente puxa. Os ataques à cadeia de fornecimento exploram exatamente essa lacuna:
- Comprometimento de lançamentos recentes. A conta de um mantenedor é comprometida e é publicada uma versão maliciosa. Estas versões são normalmente detetadas e retiradas em poucas horas a dias — razão pela qual o portão de idade recusa versões mais recentes do que um limite.
- Versões com vulnerabilidades conhecidas. O agente resolve uma dependência para uma versão com um aviso publicado. A verificação OSV apanha estas situações.
- Malware, typosquats e scripts de instalação fraudulentos. Pacotes concebidos para serem maliciosos desde o início. Os fornecedores socket.dev e Delpi sinalizam ou filtram estes, e a remoção de scripts de instalação elimina desde logo o vetor de execução mais comum.
A imposição é feita no lado do anfitrião por conceção. O proxy aplica a política à resposta antes de o agente a ver, pelo que nada em execução dentro da VM — incluindo um agente totalmente comprometido — pode afrouxar as regras. Os ficheiros .npmrc e pip.conf internos da VM só podem restringir ainda mais aquilo que o proxy já serviu, nunca ampliá-lo. As chaves de API dos serviços de reputação (socket.dev, Delpi) são mantidas apenas no anfitrião e nunca são exportadas para a VM.
Como funciona a interceção
Cada pedido de rede que a VM faz passa pelo proxy MITM do lado do anfitrião (ver Conceitos). O proxy reconhece pedidos aos principais registos de pacotes e classifica cada um:
- Metadados — a listagem de versões de um pacote (um packument npm, a API JSON ou o índice
/simple/do PyPI, uma entrada de índice esparso do Cargo, e por aí adiante). O portão de idade opera aqui, reescrevendo a listagem. - Artefacto — o ficheiro descarregável de uma versão específica: um
.tgznpm, uma wheel ou sdist Python, um.crate,.gem,.nupkgou o.zipde um módulo Go. As consultas OSV, as verificações socket.dev, a remoção de scripts e os bloqueios rígidos acontecem todos no momento da obtenção do artefacto. - Passagem direta — tudo o resto nesses anfitriões (pesquisa, autenticação). Intocado.
A interceção é automática assim que pelo menos uma camada da cadeia de fornecimento estiver ativada para o espaço de trabalho (ou o espaço de trabalho estiver inscrito com bromure.io, caso em que as obtenções são observadas para telemetria mesmo com todas as camadas de imposição desativadas). Não há nada para instalar ou configurar dentro da VM.
Nota: Os pacotes já presentes na cache local do npm ou do pip nunca chegam à rede, pelo que nada é verificado — ou registado — para eles. Um Registo de Segurança silencioso durante uma instalação pode simplesmente significar que tudo veio da cache.
Veredictos: permitir, reescrever, bloquear, reter
As camadas da cadeia de fornecimento são comutadores individuais de ligar/desligar, cada um com uma ação fixa — não existe um modo global de bloquear/avisar/permitir para este painel. (O botão de rádio de três vias registar/perguntar/bloquear que talvez conheça da Injeção de prompt, e os modos de imposição das Salvaguardas, são sistemas separados.) Cada obtenção termina num de quatro resultados:
| Resultado | O que acontece | Marcador visível |
|---|---|---|
| Permitido | A resposta passa intocada. | Visto verde no Registo de Segurança; uma linha "a inspecionar" confirma que o proxy a viu. |
| Reescrito | O proxy modificou a resposta: versões demasiado recentes removidas dos metadados, ou scripts de instalação removidos de um tarball. O gestor de pacotes prossegue normalmente. | Cabeçalho de resposta X-Bromure-Rewritten: supply-chain; linhas laranja "removido" no registo. |
| Bloqueado | O descarregamento é recusado com uma resposta HTTP 451 ("Indisponível por Razões Legais"). | Cabeçalho X-Bromure-Block: supply-chain; linha vermelha no registo. |
| Retido para consentimento | O descarregamento faz uma pausa enquanto o Bromure lhe pergunta — para passagens diretas fixadas por lockfile e para pacotes que nenhuma fonte de reputação ativada conseguiu avaliar. Negar converte a retenção num bloqueio 451. | Um alerta de consentimento do sistema; a decisão é registada. |
Um bloqueio 451 transporta um corpo em texto simples que começa por Bromure Supply-Chain Security blocked this request: seguido da razão exata, por exemplo:
Bromure Supply-Chain Security blocked this request: npm package [email protected]
published 4 hours ago — policy requires 2 days minimum
O npm, o pip, o cargo e os outros gestores de pacotes imprimem esse corpo textualmente na sua saída de erro, pelo que tanto o agente como você veem exatamente o motivo pelo qual uma instalação falhou — e o agente consegue muitas vezes contorná-lo por conta própria (por exemplo, fixando uma versão mais antiga). O estado 451 foi escolhido deliberadamente para que os bloqueios da cadeia de fornecimento sejam distinguíveis num relance dos 403 que as Salvaguardas usam.
Cobertura por ecossistema
O proxy interceta oito ecossistemas de pacotes. Nem todas as verificações suportam todos os ecossistemas:
| Ecossistema | Anfitriões intercetados | Portão de idade | OSV | socket.dev | Delpi | Remoção de scripts |
|---|---|---|---|---|---|---|
| npm | registry.npmjs.org, *.npmjs.org | Sim | Sim | Sim | Sim | Sim |
| PyPI | pypi.org, files.pythonhosted.org | Sim | Sim | Sim | — | — |
| Cargo | crates.io, static.crates.io, index.crates.io | Sim | Sim | Não | — | — |
| RubyGems | rubygems.org | Sim | Sim | Sim | — | — |
| Maven Central | repo1.maven.org, repo.maven.apache.org, search.maven.org | Não | Sim | Sim | — | — |
| NuGet | api.nuget.org, *.nuget.org | Não | Sim | Sim | — | — |
| Módulos Go | proxy.golang.org | Não | Sim | Sim | — | — |
| Packagist | repo.packagist.org, packagist.org | Sim | Sim | Sim | — | — |
Duas lacunas que vale a pena conhecer:
- Portão de idade — Maven, NuGet, Go. Estes três ecossistemas não transportam carimbos de data/hora de publicação por versão nas suas respostas de metadados padrão, pelo que os seus metadados passam sem filtragem e a rede de segurança do artefacto não tem dados sobre os quais atuar. O portão de idade efetivamente não os bloqueia hoje; npm, PyPI, Cargo, RubyGems e Packagist estão totalmente cobertos.
- socket.dev — Cargo. O socket.dev não tem suporte para Cargo. Com a filtragem socket.dev ativada, cada artefacto
crates.ionão produz veredicto e, portanto, dispara o pedido de consentimento de pacote não verificado (ver Comportamento offline e degradado). Se o seu espaço de trabalho faz muito trabalho em Rust, ou responde aos pedidos ou escolhe um fornecedor diferente.
O portão de idade
O portão de idade recusa versões de pacotes mais recentes do que um número configurável de dias, partindo do princípio de que um lançamento recém-publicado é o que tem maior probabilidade de ser um pacote acabado de comprometer — as versões maliciosas são normalmente reportadas e retiradas rapidamente, e esperar por essa janela quase não tem custo para o desenvolvimento normal. É a única camada ativada por predefinição, com um mínimo de 2 dias.
Funciona através de dois mecanismos cooperantes:
- Reescrita de metadados. O proxy remove as versões demasiado recentes da listagem de versões do registo e reaponta
lateste outras dist-tags para a versão sobrevivente mais recente. As referências flutuantes —pkg@latest, intervalos semver — nunca são, portanto, bloqueadas rigidamente: o gestor de pacotes resolve silenciosamente para a versão mais recente com idade suficiente para passar. Do ponto de vista do agente, as versões mais recentes do que o limite simplesmente ainda não existem. - Rede de segurança na obtenção do artefacto. Cada tempo de publicação por versão que o proxy vê nos metadados é guardado em cache na memória (até 50 000 entradas). Se o agente pedir depois diretamente uma versão fixada e demasiado recente, a obtenção é bloqueada com um 451 que indica a idade real do pacote e o mínimo exigido. Para o pip — cujo índice HTML PEP 503 predefinido não transporta carimbos de data/hora — o Bromure realiza uma consulta a pedido de
https://pypi.org/pypi/<pkg>/<version>/jsonpara obter o tempo de publicação.
Para o configurar, abra o painel Cadeia de fornecimento do espaço de trabalho e use o grupo Portão de idade:
- Ative Recusar pacotes mais recentes do que o limite.
- Defina Idade mínima: com o seletor (0–90 dias).
- Se um pacote específico tiver de estar instalável imediatamente — por exemplo, a sua própria equipa publica-o — adicione-o em Pacotes isentos com o botão Adicionar entrada. As entradas usam o formato de lista de permissões:
npm:axiosrestringe a isenção a um ecossistema, um simplesaxioscorresponde ao nome do pacote em todos os ecossistemas. A correspondência não distingue maiúsculas de minúsculas.
Dica: Os pedidos de metadados do npm são silenciosamente atualizados para o packument completo para que o portão possa ver os tempos de publicação — não precisa de fazer nada para o formato de metadados abreviado do npm.
Verificação de vulnerabilidades OSV
A verificação OSV consulta o ecossistema, o pacote e a versão de cada artefacto descarregado em api.osv.dev — a base de dados gratuita Open Source Vulnerabilities, que agrega a GitHub Advisory Database, os avisos do PyPI, a base de dados de vulnerabilidades do Go, o RubySec e outros. Se algum aviso para essa versão exata estiver no nível de gravidade escolhido ou acima dele, o descarregamento é bloqueado com um 451. Cobre todos os oito ecossistemas e não requer chave de API.
A gravidade é retirada da etiqueta GHSA quando o aviso tem uma; caso contrário, o Bromure calcula a pontuação base CVSS v3 a partir da string de vetor do aviso.
No grupo Verificação de vulnerabilidades OSV:
- Ative Consultar pacotes em api.osv.dev (gratuito, sem chave necessária).
- Escolha Bloquear na gravidade: — Baixa e superior, Média e superior, Alta e superior ou Apenas crítica.
A verificação está desativada por predefinição, e o limiar de gravidade tem como predefinição Alta e superior — como o próprio painel indica, um CVE de baixa gravidade num subpacote transitivo não deve interromper um fluxo de trabalho. As consultas são executadas apenas em descarregamentos de artefactos (não em obtenções de metadados), os resultados são guardados em cache na memória durante a execução da aplicação, no máximo 16 consultas são executadas em paralelo, e os erros de rede transitórios são repetidos até 5 vezes com recuo. Se o OSV não puder ser contactado de todo, o pacote é retido para o seu consentimento em vez de ser silenciosamente permitido — ver Comportamento offline e degradado.
Filtragem de pacotes: socket.dev e Delpi
O grupo Filtragem de pacotes seleciona um fornecedor de reputação através de um botão de rádio mutuamente exclusivo: Nenhum, socket.dev ou Delpi. Os dois fornecedores funcionam de formas fundamentalmente diferentes — o socket.dev é uma consulta prévia que o proxy consulta antes de deixar passar uma obtenção; o Delpi substitui completamente o registo npm. Só um pode estar ativo de cada vez por conceção (executar ambos filtraria duplamente cada instalação), e selecionar Nenhum desativa ambos, mantendo quaisquer chaves armazenadas. Independentemente do fornecedor que escolher, as outras camadas deste capítulo — portão de idade, OSV, remoção de scripts — continuam a aplicar-se por cima.
A predefinição é Nenhum. Os espaços de trabalho criados antes de o botão de rádio existir que já tenham uma chave socket.dev são automaticamente inferidos como socket.dev.
socket.dev
O socket.dev é um serviço comercial de reputação de pacotes. Com socket.dev selecionado e uma chave de API introduzida, o proxy verifica cada descarregamento de artefacto na API de problemas do socket.dev antes de o servir. Suporta npm, PyPI, Go, Maven, RubyGems, NuGet e Packagist — mas não Cargo (ver Cobertura por ecossistema).
Você traz a sua própria chave: clique em Obter uma chave de API ao lado do campo Chave de API: (abre socket.dev/dashboard/settings/api-tokens), crie um token e cole-o no campo seguro. Ambos os comutadores de bloqueio permanecem desativados até uma chave ser introduzida, e uma chave vazia desativa o socket.dev por completo, independentemente dos comutadores. A chave é armazenada no lado do anfitrião no profile.json do espaço de trabalho e nunca entra na VM; todas as consultas têm origem no seu Mac.
Estão disponíveis dois bloqueios independentes:
- Bloquear pacotes comprometidos (scripts de instalação fraudulentos, sinalizados como malware, typosquats, telemetria suspeita) — dispara nos problemas de risco da cadeia de fornecimento com forma de ataque do socket.dev. Sinais definitivos de malware (malware, malware conhecido, malware detetado por GPT, pacotes troll, chaves SSH comprometidas) bloqueiam em qualquer gravidade. Sinais com forma de ataque mais ruidosos — código ofuscado, strings suspeitas, scripts de instalação, typosquatting, acesso a shell, uso invulgar de HTTPS — bloqueiam apenas quando o socket.dev os classifica como alto ou crítico, para que um pacote com um
postinstallbenigno não seja apanhado. Sinais puros de qualidade e de atributos (novo autor, leituras de variáveis de ambiente, acesso à rede, telemetria) deliberadamente nunca bloqueiam. - Bloquear pacotes com CVEs conhecidos — dispara no balde de vulnerabilidades do socket.dev no nível do seletor Limiar de bloqueio de CVE: ou acima dele (os mesmos quatro níveis do OSV; predefinição Alta e superior).
Ambos os bloqueios estão desativados por predefinição. Os resultados são guardados em cache durante a execução da aplicação, no máximo 16 chamadas são executadas em paralelo, e as falhas transitórias são repetidas 5 vezes com recuo. Os erros de autenticação são apresentados no Registo de Segurança com o estado HTTP e uma pré-visualização do corpo da resposta.
Nota: Se ativar em conjunto o OSV e o bloqueio de CVE do socket.dev, ambos verificarão cada artefacto — isso é permitido (são camadas diferentes), apenas redundante para a cobertura de CVE. Muitos utilizadores emparelham antes o bloqueio de pacotes comprometidos do socket.dev com a verificação OSV gratuita.
Delpi
O Delpi é um registo npm seguro pronto a usar da Lupin & Holmes (landh.tech) que serve pacotes previamente avaliados. Em vez de consultar pacotes, o Bromure reencaminha cada pedido ao registo npm — metadados, tarballs, auditoria, tudo o que seja endereçado a registry.npmjs.org ou *.npmjs.org — para o registo de filtragem compatível com npm do Delpi em depi-npm-proxy.landh.tech:443, anexando a sua chave como um cabeçalho Authorization: Bearer e removendo qualquer cabeçalho Authorization que o convidado tenha enviado. O Delpi reescreve os URLs dos tarballs nos seus packuments para apontarem para si próprio, pelo que essas obtenções subsequentes também recebem a chave injetada no lado do anfitrião.
Para o ativar, selecione Delpi no botão de rádio e cole a sua chave no campo seguro Chave de API: (Obter uma chave de API abre landh.tech). Enquanto o campo estiver vazio, um aviso laranja diz Introduza uma chave de API — o Delpi permanece desativado sem uma. Cada pedido reencaminhado é registado no Registo de Segurança:
[delpi] GET registry.npmjs.org/… → https://depi-npm-proxy.landh.tech
O tratamento de erros é explícito e não silencioso:
- 401 (chave rejeitada). O Bromure substitui por um erro claro em texto simples que o npm imprime ("Bromure: the Delpi registry rejected the configured API key…", com o cabeçalho
X-Bromure-Block: delpi-auth), regista-o e emite um alerta gráfico único por combinação de espaço de trabalho e chave: "Delpi rejected your API key". As sessões SSH/TUI sem interface não recebem o alerta gráfico; dependem da linha de registo e do erro npm reescrito. - 403 (pacote bloqueado pelo Delpi, ou chave não autorizada para ele). Registado e passado sem alterações, pelo que o npm reporta o texto de recusa do próprio Delpi.
O Delpi afeta apenas o npm — os outros sete ecossistemas ficam intocados por ele. O Delpi substitui o socket.dev no botão de rádio, não a sua política local: o portão de idade, a verificação OSV e a remoção de scripts continuam a ser executados sobre aquilo que o Delpi serve.
Remoção de scripts de instalação
Os hooks preinstall, install, postinstall e prepare do npm executam código arbitrário no momento da instalação e são o cavalo de batalha do malware npm no mundo real. Com Remover preinstall / install / postinstall / prepare dos tarballs npm em tempo real ativado (no grupo Scripts de instalação), o proxy reescreve cada tarball npm em trânsito: descomprime o .tgz, localiza o package/package.json de nível superior, remove essas quatro chaves de script, recalcula a soma de verificação do cabeçalho tar e volta a comprimir com gzip.
Como os bytes do tarball mudam, o proxy também limpa dist.integrity e dist.shasum dos metadados de registo do pacote, para que o npm calcule ele próprio o hash a partir do tarball com scripts removidos e a sua verificação continue a passar para instalações não fixadas. Cada remoção é registada ("scripts de instalação removidos de" o pacote e a versão, mostrado a laranja); os tarballs que foram inspecionados e considerados limpos são marcados apenas com o cabeçalho X-Bromure-Rewritten: supply-chain. Em qualquer falha de análise, o tarball original passa intocado — esta camada falha de forma aberta, porque nunca deve inutilizar uma instalação bem formada.
Alguns pacotes precisam genuinamente de scripts de instalação — compiladores de bindings nativos como o better-sqlite3 ou o node-canvas. Adicione-os a Permitir scripts de instalação para (formato npm:better-sqlite3) e mantêm os seus hooks.
O comutador está desativado por predefinição, e aplicam-se dois limites:
- Apenas npm. As sdists do PyPI não são reescritas — o
setup.pyé código arbitrário, pelo que a remoção não é viável aí. - Apenas instalações não fixadas. Um tarball cujo hash de integridade esteja fixado no
package-lock.jsonnão pode ser reescrito sem falhar a verificação. Esse caso é regido pela camada seguinte.
Instalações fixadas por lockfile
Uma instalação fixada por lockfile — npm ci — fixa o hash de integridade de cada tarball no lockfile. O Bromure não consegue reescrever esses tarballs sem quebrar a verificação do hash, pelo que as suas únicas opções são passá-los sem modificação ou bloqueá-los. Por predefinição, passam silenciosamente.
Se quiser ter uma palavra a dizer, ative Perguntar antes de passar sem modificação os tarballs fixados por lockfile (npm ci, pip --require-hashes) no grupo Instalações fixadas por lockfile. A primeira obtenção fixada por lockfile num lote (detetada para o npm através do cabeçalho de pedido npm-command: ci) faz então surgir uma caixa de diálogo de consentimento no anfitrião intitulada Passar npm ci (instalação fixada por lockfile) do espaço de trabalho "…"? com os botões Permitir durante 15 minutos, Permitir uma vez, Permitir durante o resto da sessão e Não permitir. Toda a rajada de obtenções concorrentes converge para esse único pedido e segue a sua decisão; negar bloqueia a obtenção com um 451 e a negação é lembrada durante 60 segundos para que as repetições não voltem a perguntar.
Nota: Apesar de a etiqueta da interface mencionar
pip --require-hashes, a deteção está atualmente implementada apenas para o cabeçalhonpm-command: cido npm — as instalações pip fixadas por hash não acionam o pedido. (Também nunca são reescritas, uma vez que os artefactos do PyPI nunca são modificados.)
Pedidos de consentimento e concessões
Todos os caminhos da cadeia de fornecimento que pedem ao utilizador — a passagem direta fixada por lockfile e a retenção de pacote não verificado descrita abaixo — passam por um corretor de consentimento partilhado com convergência de rajadas: os pedidos concorrentes para o mesmo âmbito aguardam numa única caixa de diálogo em vez de empilhar alertas. Cada pedido oferece as mesmas quatro decisões:
| Decisão | Efeito |
|---|---|
| Não permitir | Bloqueia com um 451; lembrado durante 60 segundos, negando automaticamente as repetições imediatas. |
| Permitir uma vez | Deixa passar este único pedido (ou rajada convergida). |
| Permitir durante 15 minutos | Concede o âmbito durante 15 minutos. |
| Permitir durante o resto da sessão | Concede o âmbito até a aplicação sair. |
As concessões e negações ativas são listadas como Decisões da cadeia de fornecimento — separadas das decisões de salvaguarda — na interface de aprovações (a área Janela → Aprovações de Credenciais…), onde pode revogar uma concessão antecipadamente. As concessões existem apenas em memória e não sobrevivem a um reinício da aplicação.
Nas sessões SSH/CLI remotas não há caixa de diálogo gráfica: a mesma pergunta é apresentada como um seletor dentro do tmux do espaço de trabalho. A ausência de resposta significa negar. Ver Acesso Remoto.
Configurar a política
A política da cadeia de fornecimento é configurada por espaço de trabalho, no painel Cadeia de fornecimento da janela Editar espaço de trabalho (o ícone amarelo de caixa de envio na barra lateral). A referência completa campo a campo encontra-se em definições da Cadeia de fornecimento; as predefinições num relance:
| Definição | Predefinição |
|---|---|
| Recusar pacotes mais recentes do que o limite (portão de idade) | Ativado, Idade mínima: 2 dias, sem isenções |
| Consultar pacotes em api.osv.dev (gratuito, sem chave necessária) | Desativado; Bloquear na gravidade: Alta e superior |
| Filtragem de pacotes | Nenhum (sem chave socket.dev ou Delpi) |
| Bloquear pacotes comprometidos / Bloquear pacotes com CVEs conhecidos (socket.dev) | Desativado; Limiar de bloqueio de CVE: Alta e superior |
| Remover preinstall / install / postinstall / prepare dos tarballs npm em tempo real | Desativado, lista de permissões vazia |
| Perguntar antes de passar sem modificação os tarballs fixados por lockfile | Desativado (passagem direta silenciosa) |
Três detalhes operacionais:
-
As edições aplicam-se ao vivo. Guardar o espaço de trabalho envia a nova política para as sessões em execução imediatamente — o proxy lê-a a cada pedido, pelo que nunca é necessário reiniciar a VM. Cada política nova ou alterada é confirmada com um resumo de uma linha no Registo de Segurança, por exemplo:
[supply-chain] policy engaged for 1a2b3c4d: age-gate=2d osv=high socket.dev=compromised+cve=high strip-scriptsAs configurações incorretas são assinaladas mesmo nesse resumo:
socket.dev=key-set-but-no-togglesignifica que uma chave foi introduzida mas nenhum dos bloqueios está ativado, edelpi=selected-but-no-keysignifica que o Delpi está escolhido mas desativado por falta de chave. -
Onde é armazenada. A política reside no
profile.jsondo espaço de trabalho em~/Library/Application Support/BromureAC/profiles/<id>/(apenas os campos não predefinidos são escritos). As chaves de API do socket.dev e do Delpi são armazenadas aí também — apenas no lado do anfitrião, mostradas como campos seguros na interface, e nunca copiadas para a VM. Não há variáveis de ambiente ou argumentos de arranque específicos da cadeia de fornecimento. -
Configuração remota. O menu remoto SSH/TUI expõe o mesmo painel Cadeia de fornecimento com os mesmos campos, pelo que uma instância sem interface pode ser configurada sem a interface gráfica. Ver Acesso Remoto.
A janela do Registo de Segurança
Tudo o que o pipeline da cadeia de fornecimento faz é visível no Registo de Segurança — abra Janela → Registo de Segurança…. É um acompanhamento ao vivo de cada evento de segurança que o proxy emite: consultas e veredictos da cadeia de fornecimento, bloqueios 451, remoções de scripts, confirmações de política ativada e reencaminhamentos do Delpi, a par de deteções de injeção de prompt, ativação/desativação do Fusion, alterações de encaminhamento de LLM, eventos de acesso remoto e linhas de worktree. Uma janela serve toda a aplicação; escolher o item de menu novamente traz-na para a frente.
As linhas têm código de cores para que possa ler uma instalação num relance:
| Cor | Significado | Marcador |
|---|---|---|
| Azul | Consulta de saída (OSV, socket.dev, rede de segurança do tempo de publicação) | → |
| Verde | Veredicto limpo — o pacote passou | ✓ |
| Vermelho | Bloqueio ou falha (451, erro) | ✗ |
| Laranja | Scripts de instalação removidos de um tarball | "removido" |
| Destaque | Política ativada / alterada | [supply-chain] |
A janela tem um campo Filtrar… para restringir a vista (escreva um nome de pacote, um ecossistema ou qualquer texto das linhas que lhe interessam), uma caixa de verificação Deslocamento automático (ativada por predefinição; desassinale-a para deixar de acompanhar o final enquanto lê), um botão Limpar que apaga o buffer, e um rodapé que mostra a contagem de entradas ("42 entradas", ou "7 de 42 entradas" enquanto um filtro está ativo). Uma mensagem de estado vazio explica quando as entradas aparecerão.
Para o ver em ação: abra a janela, execute qualquer instalação dentro de uma sessão (npm install, pip install, cargo add, gem install, …), e observe as entradas a fluir. Uma instalação totalmente limpa ainda produz linhas "a inspecionar" para cada artefacto — isso é deliberado, para que um pipeline silencioso seja distinguível de um que foi contornado.
Nota: O buffer é um anel em memória limitado a cerca de 5000 linhas e não persiste entre reinícios da aplicação. Cada linha é também espelhada para o stderr da aplicação, pelo que lançar o
bromure-clia partir de um terminal (ou capturar a sua saída de registo) lhe dá uma cópia duradoura. A janela abre a 820×460 e pode ser redimensionada até 720×360.
Comportamento offline e degradado
As verificações de reputação do pipeline dependem de chamadas de saída a partir do seu Mac (nunca a partir da VM): api.osv.dev para o OSV, api.socket.dev para o socket.dev, pypi.org para a rede de segurança do tempo de publicação do PyPI, e depi-npm-proxy.landh.tech para o Delpi. Quando uma fonte ativada não consegue produzir um veredicto — rede em baixo após repetições, erro HTTP, limitação de taxa, uma falha de autenticação ou um ecossistema não suportado — o Bromure falha de forma fechada em vez de permitir silenciosamente.
O descarregamento faz uma pausa e uma retenção de pacote não verificado pergunta-lhe, por pacote e versão, com um alerta do sistema intitulado Passar um pacote não verificado do espaço de trabalho "…"?: o Bromure não conseguiu contactar a fonte para avaliar o pacote, e instalá-lo significa aceitar um pacote que não foi verificado face às suas fontes de reputação configuradas. Aplicam-se as quatro decisões de consentimento padrão; negar (incluindo quando não há interface gráfica disponível e o pedido remoto expira) bloqueia com um 451. As retenções são indexadas por pacote@versão, pelo que uma aprovação nunca pode abranger todo o grafo de dependências.
Esta é uma proteção deliberada: sem ela, um atacante que consiga induzir limitação de taxa no serviço de reputação poderia contrabandear pacotes sem verificação. As consequências práticas:
- Trabalhar totalmente offline com o OSV ou o socket.dev ativado significa um pedido para cada pacote não guardado em cache. Desative essas camadas para períodos offline — o portão de idade continua a funcionar a partir de metadados já em cache sem conectividade.
- socket.dev mais Cargo significa um pedido para cada crate, uma vez que o socket.dev não consegue avaliar Cargo de todo (as concessões são por pacote@versão, pelo que uma concessão de sessão cobre apenas essa versão de crate).
- A rede de segurança do tempo de publicação do PyPI é a única exceção: num erro de rede puro, falha de forma aberta para essa obtenção (a falha não é guardada em cache, pelo que a consulta é repetida da próxima vez). A reescrita de metadados do portão de idade não é afetada.
Deteção de comprometimento
As verificações da cadeia de fornecimento reduzem as probabilidades de código hostil entrar no sandbox; a deteção de comprometimento apanha o momento em que código hostil que de facto entrou tenta agir. Faz parte do sistema de credenciais em vez do pipeline de pacotes — o retrato completo das credenciais-engodo e da troca de token está em Credenciais — mas o seu alarme é documentado aqui porque um pacote envenenado é o seu gatilho mais provável.
Cada pedido de saída da VM é examinado numa única passagem em busca dos tokens engodo ("falsos") que a camada de troca de credenciais cunhou. Um falso restringido a um anfitrião (digamos, github.com) que apareça num pedido destinado a qualquer outro anfitrião é a assinatura de exfiltração de credenciais. Quando isso acontece:
- O proxy bloqueia o pedido com um 451 — o destino nunca recebe um byte.
- A VM é pausada instantaneamente. Se a sessão estava desanexada, é forçadamente reanexada e revelada. O fotograma congelado da sessão fica tingido de vermelho.
- Surge um alerta crítico, intitulado Este ambiente pode ter sido comprometido, explicando que o Bromure detetou uma tentativa de saída para vazar uma credencial de sessão do espaço de trabalho nomeado para um anfitrião para o qual não foi cunhada e que a VM foi pausada — com uma linha de detalhe por vazamento: uma pré-visualização do token (como
sk-a…f9q3), o nome da credencial, o anfitrião para o qual foi cunhada, e o anfitrião para o qual foi observada a dirigir-se.
O alerta oferece três respostas:
- Encerrar (a predefinição) — para a VM e marca o espaço de trabalho como comprometido.
- Guardar para Investigação — escolhe uma pasta; o Bromure exporta
disk.img(uma cópia do disco de sistema da VM),home.tar.gz(o diretório home do espaço de trabalho) eshares/<name>.tar.gzpara cada pasta partilhada, depois encerra e marca o espaço de trabalho como comprometido. O estado da RAM é descartado. - Continuar — aceitar o risco e retomar; o detetor volta a disparar se acontecer novamente. Esc e Cmd-. deliberadamente não mapeiam para Continuar — retomar uma VM possivelmente hostil tem de ser um clique explícito.
Um espaço de trabalho marcado como comprometido recusa-se a arrancar novamente até você o limpar explicitamente, e o fluxo de limpeza avisa que as pastas partilhadas não são limpas — podem ainda conter ficheiros contaminados, pelo que as deve rever à mão.
Não há nada para configurar: a deteção está sempre ativa para credenciais que declaram um âmbito de anfitrião. As credenciais manuais sem um anfitrião fixado ("qualquer anfitrião") nunca a podem acionar, e os tokens Claude/Codex usam uma correspondência relaxada de mesmo domínio registado (um token cunhado para api.anthropic.com visto noutro anfitrião anthropic.com não dispara o alarme). Apenas um alerta é mostrado de cada vez; os eventos repetidos enquanto está aberto são descartados.
Visibilidade empresarial
Para espaços de trabalho inscritos com bromure.io, cada obtenção de metadados e de artefacto também emite um evento supply_chain.fetch para o fluxo de eventos empresarial, transportando o ecossistema, o pacote, a versão, o tipo de pedido, o resultado (allowed, rewritten, blocked ou stripped) e o tipo de razão (age_gate, osv, socket_compromised, socket_cve, verify_unavailable, lockfile_denied, scripts_stripped). Só a inscrição dá aos administradores visibilidade dos descarregamentos de pacotes de toda a organização — um inventário de tudo o que cada agente instalou — mesmo em espaços de trabalho com todas as camadas de imposição desativadas.
Como funciona a inscrição, e o que os administradores veem do outro lado, é abordado em Empresa.