# Como uma compilação local sem assinatura deve obter aprovação?

Uma compilação local sem assinatura não é automaticamente suspeita. Ela também não tem uma identidade reconhecível. Essas duas coisas precisam coexistir, ou seu fluxo de aprovação cairá em um de dois maus hábitos: pessoas desenvolvedoras aprovam todo processo anônimo porque precisam trabalhar, ou desistem e executam agentes com credenciais diretas.

A pergunta útil é mais específica: que evidências permitem que uma pessoa aprove *esta execução específica* de um agente compilado localmente sem fingir que todo processo vindo de uma pasta conhecida merece o mesmo nível de confiança? A resposta é um fluxo baseado em limites de sessão, origem da inicialização, escopo das credenciais e disposição para recusar solicitações que não conseguem se explicar.

## Sem assinatura é uma declaração ausente, não uma classificação de risco

Um código sem assinatura não fez uma declaração de identidade respaldada por um publicador que possa ser verificada por uma cadeia de certificados. Isso, por si só, não diz se o código é malicioso, revisado, modificado localmente ou recém-compilado a partir do repositório que está aberto. Apenas remove um tipo de evidência.

As equipes erram nas duas direções. Um grupo trata qualquer executável sem assinatura como hostil, empurrando o desenvolvimento normal para canais paralelos e chaves de API pessoais. Outro trata «sem assinatura» como sinônimo de «meu código local», criando uma categoria ampla de aprovação que um processo não relacionado pode explorar.

Mantenha estas distinções separadas:

- **Identidade do publicador** responde quem assinou uma compilação distribuída.
- **Origem da compilação** responde qual código-fonte, revisão, máquina e comando produziram este executável.
- **Origem em tempo de execução** responde o que iniciou o processo que está solicitando acesso agora.
- **Autoridade da ação** responde qual credencial ou acesso remoto esse processo pode usar.

Uma assinatura pode ajudar com a primeira pergunta. Um fluxo local bem estruturado precisa responder às outras três. Quando uma pessoa desenvolvedora compila um cliente de agente a partir de um worktree, sua confiança costuma vir do estado do repositório e do comando que acabou de executar, não de um certificado público. A experiência de aprovação deve mostrar essas evidências, em vez de tratar a ausência de um certificado como um veredito.

A documentação de assinatura de código da Apple deixa o mesmo limite claro de forma mais formal. Um requisito designado identifica uma instância de código assinado segundo a política que o verifica; ele não prova que o código é adequado para todo recurso ou toda ação futura. A Apple também observa que cada subsistema do macOS aplica sua própria política de confiança. Por isso, um gateway de ações deve evitar transformar o status da assinatura em uma decisão universal de permissão.

## Uma faixa para compilações locais precisa de evidências que outro processo não possa reutilizar

Dê aos clientes de agentes compilados localmente sua própria faixa de aprovação. Não os coloque em uma categoria chamada «sem assinatura», «desenvolvimento» ou «terminal». Esses rótulos descrevem processos demais para serem úteis.

Antes de aprovar uma sessão, a faixa deve solicitar quatro evidências:

1. O caminho do executável deve estar dentro de um checkout controlado pela pessoa desenvolvedora ou de um diretório de saída da compilação.
2. O processo pai deve ser um inicializador esperado, normalmente um terminal, uma tarefa da IDE ou um script wrapper pertencente à equipe.
3. O estado do repositório e o comando de compilação devem ser fáceis de verificar, sem precisar reconstruir o dia de memória.
4. O destino solicitado e a credencial devem corresponder ao trabalho em andamento.

Nenhum desses sinais é perfeito sozinho. Juntos, eles dificultam que um download aleatório, um auxiliar em segundo plano ou uma dependência comprometida se passe por uma execução local rotineira.

É aqui que as equipes costumam recorrer a um mecanismo de políticas: permitir caminhos sob um diretório, aceitar comandos cujo nome começa com `agent`, isentar tudo que seja iniciado por uma determinada IDE. Não faça isso. Uma regra estática é atraente porque elimina interrupções, mas transforma uma decisão fácil de revisar em uma exceção permanente. Qualquer processo que consiga organizar o caminho ou a cadeia de processos pai correta herda a exceção.

Use aprovação humana no limite da sessão. O cartão de aprovação deve mostrar a autoridade de assinatura do processo quando ela existir, mas uma compilação sem assinatura precisa de outro contexto ao lado desse campo: caminho do executável, comando pai, diretório de trabalho quando disponível e destino que pretende alcançar. Assim, a pessoa desenvolvedora pode responder a uma pergunta real: «Este é o cliente que acabei de compilar para esta tarefa?»

A autorização por sessão do Sallyport se encaixa nessa faixa porque solicita aprovação uma vez para um novo processo de agente e a mantém apenas até o processo terminar. A unidade de decisão é a identidade do processo, não uma classe vaga de software sem assinatura.

## Um caminho conhecido é evidência, não identidade

Um caminho como `~/src/agent-client/dist/agent` parece tranquilizador porque conta uma história plausível. Ele não é um limite de identidade. Um processo malicioso pode ser executado nesse caminho se conseguir gravar ali, substituir uma saída, alterar um link simbólico ou convencer um inicializador a resolver outro executável.

Comece tornando a história legítima simples e repetível. Cada pessoa desenvolvedora deve ter um local normal para o checkout. A saída da compilação deve permanecer dentro desse checkout ou em um diretório previsível no qual apenas a conta da pessoa possa gravar. Evite diretórios de compilação compartilhados, Downloads, diretórios temporários, pastas sincronizadas e raízes de projetos nas quais scripts de pacotes reescrevem executáveis rotineiramente.

Um contrato prático de inicialização pode ser tão pequeno quanto este:

```sh
#!/bin/zsh
set -eu

repo="$HOME/src/agent-client"
cd "$repo"

git status --short
git rev-parse --short HEAD
exec ./build/agent-client --mcp
```

A parte útil não é a sintaxe do shell. É a evidência que ela deixa. O shell pai tem um caminho de script conhecido, o diretório de trabalho aponta para um checkout, a revisão do Git é exibida antes de o cliente começar e `exec` substitui o shell pelo programa pretendido, em vez de deixar uma cadeia de processos confusa.

Não permita que esse script baixe uma versão, escolha uma branch a partir de uma variável de ambiente, execute um hook do gerenciador de pacotes ou consulte um arquivo de configuração mutável fora do checkout. Essas conveniências tornam o contrato de inicialização menos útil, porque a pessoa que revisa a aprovação já não consegue saber o que o script realmente selecionou.

Se o cliente do agente precisar de código gerado, gere-o como parte do comando de compilação explícito. Se precisar de um arquivo de configuração local, passe o caminho do arquivo de forma visível e mantenha-o fora do repositório apenas quando contiver configurações específicas da máquina. Não esconda credenciais nele. O gateway existe para que o cliente não precise delas.

## Inspecione o processo antes de aprovar a sessão

Uma boa decisão de aprovação leva segundos, mas não deve depender da memória. Quando um novo processo local pedir para chamar uma API ou abrir uma conexão SSH, inspecione o executável e a cadeia de processos pai antes de clicar em aprovar.

No macOS, estes comandos oferecem uma primeira verificação útil. Substitua o PID de exemplo pelo PID mostrado pelo visualizador de processos ou pelo terminal:

```sh
pid=48271

ps -o pid=,ppid=,user=,lstart=,command= -p "$pid"
ps -o pid=,ppid=,command= -p "$(ps -o ppid= -p "$pid" | tr -d ' ')"
lsof -a -p "$pid" -d cwd -Fn
```

O formato da saída deve ser parecido com este:

```text
48271 47990 alex Tue Jul 22 10:14:03 2026 /Users/alex/src/agent-client/build/agent-client --mcp
47990 23112 /bin/zsh /Users/alex/src/agent-client/scripts/run-local-agent
n/Users/alex/src/agent-client
```

Você está verificando uma cadeia, não colecionando detalhes. O binário deve estar no local de compilação esperado. O pai deve ser seu inicializador conhecido. O diretório atual deve corresponder ao checkout. Um processo vindo de `/private/var/folders`, `~/Downloads`, um cache de pacotes desconhecido ou um wrapper inesperado não passou na revisão, mesmo que o nome do comando pareça correto.

Depois, inspecione o próprio executável:

```sh
client="$HOME/src/agent-client/build/agent-client"
file "$client"
codesign --display --verbose=4 "$client" 2>&1 | sed -n '1,18p'
shasum -a 256 "$client"
```

Um binário sem assinatura pode fazer o `codesign` informar que ele não está assinado. Um binário assinado ad hoc informa uma assinatura sem uma autoridade pública de assinatura. Isso ainda é uma informação útil, mas não a interprete como uma identidade da equipe. A Apple descreve a assinatura ad hoc como «Sign to Run Locally» e explica que seu requisito designado está vinculado àquela versão específica do código. Uma nova compilação muda as evidências, exatamente por isso a aprovação da sessão não deve sobreviver à substituição do processo.

O hash é uma ferramenta de comparação, não um sinal de confiança. Ele ajuda quando duas pessoas desenvolvedoras precisam confirmar que executaram a mesma saída a partir da mesma revisão. Ele não torna um binário seguro só porque há 64 caracteres hexadecimais ao lado dele.

A pessoa desenvolvedora deve recusar a solicitação se qualquer parte da cadeia for inesperada. Não aprove primeiro para investigar depois da chamada à API. A aprovação é o momento em que a incerteza deve custar alguns minutos, não uma investigação de incidente.

## Use a sessão como limite entre uma compilação e a próxima

O limite da sessão resolve um problema que as listas de permissão por caminho não resolvem: o código local muda constantemente. Uma pessoa desenvolvedora pode recompilar o cliente dez vezes em uma hora. Cada saída pode ter um grafo de dependências diferente, um tratamento de comandos diferente ou uma branch de depuração temporária que envia solicitações para um destino inesperado.

Torne o processo de inicialização descartável. Inicie o cliente do agente para uma tarefa, aprove esse processo depois da revisão e deixe a aprovação expirar quando ele terminar. Quando a pessoa desenvolvedora recompilar, trocar de branch, modificar o wrapper ou reiniciar o cliente, terá um novo processo e uma nova decisão de aprovação.

Isso só parece inconveniente quando a sessão é mal definida. Se um cliente de agente inicia e para a cada chamada individual de ferramenta, corrija o ciclo de vida do cliente ou use um supervisor local planejado que permaneça transparente na árvore de processos. Não resolva a frequência tornando a aprovação permanente. Um processo de curta duração deve ter curta duração.

O fluxo abaixo funciona bem para uma pessoa desenvolvedora que executa um agente de programação compilado localmente contra um ambiente de teste:

1. Compile a partir do checkout e mostre a revisão e quaisquer alterações não confirmadas.
2. Inicie pelo script wrapper versionado no repositório.
3. Na primeira solicitação de autorização, confirme o caminho exibido do processo, o comando pai e o serviço de destino.
4. Aprove a sessão se esses detalhes corresponderem à tarefa.
5. Encerre o cliente quando a tarefa terminar e depois recompile ou reinicie para a próxima tarefa distinta.

Esse fluxo oferece um caminho de recuperação claro. Se uma compilação parecer duvidosa, interrompa-a. Não há uma permissão oculta para desfazer nem um arquivo de regras que tenha acumulado silenciosamente exceções para metade da equipe.

Não confunda a aprovação de uma sessão com a aprovação de um repositório. Um repositório pode estar limpo enquanto o comando de inicialização está errado. Um comando de inicialização pode estar correto enquanto a branch é experimental. Uma decisão de sessão diz que este processo, com este contexto, pode fazer chamadas comuns durante a execução atual.

## Reserve a aprovação por chamada para consequências irreversíveis

A aprovação de sessão é o padrão adequado para tráfego de desenvolvimento repetível: ler metadados de issues, consultar uma API de sandbox, buscar um repositório por SSH ou atualizar um registro de teste descartável. Exigir um gesto humano em cada uma dessas chamadas ensina as pessoas a aprovar sem ler.

Algumas credenciais ainda devem exigir aprovação a cada uso. Escolha-as com base na consequência da ação remota, não no teatro de sensibilidade em torno do segredo.

Use aprovação por chamada para credenciais que possam:

- gravar em um ambiente de produção;
- publicar um pacote, uma versão ou um artefato de implantação;
- acessar uma exportação de dados de clientes ou outro conjunto concentrado de dados sensíveis;
- alterar a participação na organização, configurações de autenticação ou controles de recuperação;
- alcançar um host SSH de produção.

Não marque todos os tokens de API de desenvolvimento dessa forma. Isso cria fadiga de aprovação, e a fadiga transforma uma pessoa revisora cuidadosa em alguém que apenas aperta botões. O gateway deve tornar os momentos perigosos distintos o suficiente para que as pessoas percebam.

Os detalhes da solicitação importam tanto quanto a segunda confirmação. Para HTTP, mostre o método e o destino, além de uma parte suficiente do caminho para identificar a ação sem despejar conteúdo sensível da solicitação na tela de aprovação. `GET /v1/test-runs/123` e `DELETE /v1/projects/123` nunca devem parecer iguais. Para SSH, mostre o host e a conta, e peça que a pessoa desenvolvedora confirme por que esse host pertence à tarefa atual.

Uma exigência por chamada também é um freio útil para um cliente modificado localmente. Você pode se sentir confortável aprovando uma sessão de uma nova compilação experimental que lê dados de um serviço de staging. Ainda assim, deve hesitar antes de permitir que essa mesma compilação publique uma versão em produção. Essa hesitação é o objetivo.

## Trate recompilações, trocas de branch e wrappers como novas evidências

As pessoas desenvolvedoras costumam tomar uma decisão de aprovação pela manhã e depois mudar os fatos ao longo do dia. Elas baixam uma branch, executam um gerador de código, atualizam dependências, alteram um arquivo de prompt, adicionam um alias de shell ou substituem um script wrapper. O binário pode manter o mesmo nome e caminho enquanto seu comportamento muda de forma relevante.

Adote uma regra simples: se o executável, seu inicializador ou o ambiente pretendido mudar, encerre a sessão e reinicie. Não é preciso uma cerimônia formal para cada edição. É preciso disciplina para não carregar o contexto de ontem para uma nova compilação.

Há três eventos que merecem uma pausa automática no seu próprio fluxo:

- Você alterou a branch, o commit, o arquivo de bloqueio de dependências ou a saída gerada.
- Você alterou o script que inicia o cliente ou as variáveis de ambiente que moldam seu comportamento.
- O agente agora quer um host de API diferente, um host SSH diferente ou uma credencial com consequências mais amplas.

Uma troca de branch é subestimada porque o nome do binário permanece estável. Ainda assim, uma branch de funcionalidade pode conter uma integração experimental, um manifesto de ferramentas modificado ou um endpoint de depuração. A resposta não é proibir branches. É tornar visível e revisável a primeira solicitação da nova execução.

As variáveis de ambiente merecem a mesma desconfiança que os argumentos do executável. Um cliente iniciado com `API_BASE_URL`, `SSH_AUTH_SOCK`, `PATH`, `DYLD_*` ou um local de configuração personalizado pode se comportar de maneira diferente do código-fonte que você inspecionou. Seu wrapper deve definir apenas as variáveis de que o cliente precisa, exibir valores não secretos que afetem o roteamento e rejeitar valores ausentes, em vez de carregar um perfil de shell cheio de configurações.

Por exemplo, isto é revisável:

```sh
export AGENT_ENVIRONMENT=staging
export AGENT_API_ORIGIN=https://staging.example.internal
exec ./build/agent-client --mcp
```

Isto não é:

```sh
source "$HOME/.agent-env"
eval "$(tooling configure-agent)"
exec "$AGENT_BIN" "$@"
```

A segunda forma pode ser conveniente, mas esconde o executável, a origem da configuração, os argumentos e os efeitos colaterais. Ela obriga a pessoa que aprova o processo a confiar em uma pilha de indireções. O desenvolvimento local já tem componentes suficientes.

## Mantenha as credenciais fora do cliente, mesmo quando o cliente é seu

Um cliente compilado localmente é mais fácil de confiar quando nunca recebe a credencial que pretende usar. Se o cliente lê um token de API de uma variável de ambiente ou uma chave SSH de um arquivo, pode imprimi-lo, encaminhá-lo, armazená-lo em cache, incluí-lo em um relatório de falha ou entregá-lo a um subprocesso. A confiança da pessoa desenvolvedora na própria compilação não muda essa exposição.

Coloque o segredo no gateway de ações e permita que o cliente solicite uma ação por referência. O cliente deve fornecer o contexto da solicitação HTTP ou do comando SSH necessário para realizar o trabalho. O gateway injeta a credencial, executa a chamada e devolve o resultado. Assim, a decisão de aprovação se concentra na ação, e não em saber se o cliente pode manter um token de acesso por tempo indefinido.

Para HTTP, estabeleça credenciais separadas para ambientes e finalidades distintas. Um token de staging não deve alcançar a produção apenas porque o cliente forneceu outro host. Para SSH, use entradas de host ou registros de credenciais distintos para funções distintas. Não dependa de uma única chave com acesso total e de uma promessa humana de selecionar o destino correto.

O Sallyport mantém as credenciais de API e SSH em um cofre criptografado e executa a própria ação, para que o agente receba resultados, não segredos em texto simples. Esse desenho é especialmente importante para compilações locais, nas quais alterações no código são esperadas e uma variável de ambiente vazada pode estar a apenas uma impressão de depuração de distância.

A separação também melhora a resposta a incidentes. Se um cliente se comportar de forma estranha, você pode interromper ou revogar a sessão sem trocar todos os segredos que ele talvez tenha carregado na memória. A barreira do cofre continua absoluta enquanto ele está bloqueado, e um gateway bloqueado recusa ações em vez de tentar inferir a intenção da pessoa desenvolvedora.

## O registro de auditoria deve resolver divergências, não apenas coletar eventos

Quando um fluxo de aprovação de compilação local funciona, às vezes alguém perguntará por que um agente acessou um serviço ou se um processo ainda estava em execução depois de uma transferência. A resposta deve vir de um registro de eventos, não de suposições, do histórico do terminal ou de uma mensagem escrita depois do fato.

Registre duas visões da mesma atividade subjacente. Uma deve mostrar as execuções dos agentes e permitir a revogação imediata. A outra deve mostrar ações HTTP e SSH individuais. Mantenha as evidências vinculadas para que uma pessoa revisora possa passar de uma solicitação suspeita à sessão que a autorizou e, depois, ao contexto do processo que levou à decisão.

Um log à prova de adulteração é especialmente útil aqui, porque as compilações locais podem ser modificadas pelas mesmas pessoas que as revisam. O Sallyport projeta seus diários de Sessões e Atividade a partir de um único log de auditoria criptografado e encadeado por hash, e `sp audit verify` verifica essa cadeia offline sobre o texto cifrado sem exigir uma chave do cofre. Isso dá à equipe uma verificação de integridade mesmo quando a pessoa revisora não deve receber acesso aos segredos por trás das ações.

Execute a verificação como parte de uma revisão ou simulação de incidente:

```sh
sp audit verify
```

O resultado esperado é uma confirmação clara ou um relatório que identifique um problema na cadeia. Trate uma falha de verificação como um problema operacional até entendê-la. Não exclua o diário, reinstale o aplicativo nem aceite uma nova linha de base antes de preservar os registros afetados.

O diário não substitui a revisão no momento da aprovação. Ele oferece uma forma de testar se o seu processo está produzindo evidências que você realmente pode usar. Se o log disser apenas que «um cliente sem assinatura» fez uma chamada, melhore o contrato de inicialização e o contexto da aprovação. Se mostrar o processo, a sessão, o destino, o horário e a ação, a equipe poderá investigar sem transformar o computador de cada pessoa em um projeto forense.

## Convenções da equipe impedem que os avisos de aprovação se tornem ruído de fundo

A parte mais difícil de um fluxo de aprovação de compilação local não é a linha de comando. É preservar o significado humano de uma aprovação depois de meses de trabalho normal.

Escreva uma pequena convenção para agentes locais e mantenha-a perto do repositório, não escondida em um manual de segurança. Ela deve indicar onde ficam os checkouts aceitos, como são os scripts de inicialização, quais ambientes contam como desenvolvimento comum, quais credenciais exigem aprovação por chamada e o que fazer quando o aviso mostrar um processo inesperado.

Torne normal o caminho de recusa. Uma pessoa desenvolvedora que clica em recusar porque um processo pai parece estranho não deve sentir que bloqueou o progresso. Ela deve interromper o processo, inspecioná-lo, reiniciar pelo wrapper conhecido e aprovar a execução limpa. Isso é mais rápido do que normalizar um processo misterioso e tentar explicá-lo depois.

Revise a convenção depois de uma surpresa real: um script de pacote reescreveu uma saída, uma IDE iniciou um auxiliar inesperado, uma branch apontou para o ambiente errado ou um agente solicitou uma credencial fora da tarefa. Essas falhas são úteis porque revelam quais evidências estavam faltando. Não responda adicionando uma regra de permissão permanente. Aperte o contrato de inicialização, melhore o que a tela de aprovação mostra ou reduza o escopo da credencial.

Uma pessoa desenvolvedora que compila seu próprio agente não deveria ter de escolher entre teatro de segurança e interrupções constantes. Ofereça uma aprovação de sessão específica para um processo visível, mantenha as chamadas de maior consequência atrás de uma decisão separada e exija uma nova revisão sempre que a história da compilação local mudar. Isso é rigoroso o suficiente para detectar o processo errado e prático o suficiente para que as pessoas continuem usando o fluxo.
