UpuaiUpuai

Por que a Upuai não pede acesso de escrita ao seu código no GitHub

Até julho de 2026, conectar a Upuai ao GitHub pedia escrita em todos os repositórios. Hoje são três permissões de leitura. Quais são, o que elas nos impedem, e por que no GitLab ainda não é assim.

Equipe Upuai· Upuai Cloud13 min de leitura

Quando você conecta uma plataforma de deploy ao seu GitHub, existe uma tela que quase ninguém lê com atenção e que decide tudo: a tela de permissões. É nela que fica escrito se você acabou de dar leitura em um repositório ou escrita em todos.

Até 30 de julho de 2026, a nossa tela do GitHub era da segunda espécie. Quem conectava a Upuai pedindo deploy via um pedido de acesso de escrita a todos os repositórios da conta, sem opção de escolher quais. Um cliente reclamou, com razão, e a integração foi reescrita. Hoje a Upuai usa um GitHub App e pede três permissões, as três somente leitura, nos repositórios que você marcar. Este post mostra quais são, por que a versão antiga era daquele jeito, e a parte que costuma faltar em texto de fornecedor: o que a permissão mínima nos impede de fazer.

Um aviso de escopo antes de começar: tudo o que vem abaixo vale para o caminho GitHub. No GitLab a conexão ainda é OAuth com um escopo amplo, e há uma seção só sobre isso mais adiante.

A tela antiga: um scope que não dava para dividir

A integração antiga era um OAuth App clássico, e para clonar repositório privado um OAuth App só tem um caminho: o scope repo. A documentação do GitHub descreve esse scope assim:

Grants full access to public and private repositories including read and write access to code, commit statuses, repository invitations, collaborators, deployment statuses, and repository webhooks.

Leitura e escrita, código, colaboradores, webhooks, tudo junto. Não existe metade de repo: ou você concede o pacote inteiro, em todos os repositórios da conta, ou não conecta.

O detalhe que torna a história menos sinistra e mais constrangedora é o que a gente fazia com aquele poder. Dos catorze métodos do nosso cliente de GitHub, doze eram leitura pura. Os dois que escreviam serviam para criar e remover o webhook de deploy dentro do seu repositório. Ou seja: a Upuai pedia autorização para reescrever qualquer linha de qualquer projeto seu, e usava isso para cadastrar uma URL de callback.

O próprio GitHub recomenda o caminho oposto: “Consider building a GitHub App instead of an OAuth app. GitHub Apps use fine-grained permissions instead of scopes, which give you more control over what your app can do.”

As três permissões que a Upuai pede hoje

O App se chama Upuai Cloud e é público: você pode abrir github.com/apps/upuai-cloud agora, sem ser cliente, e ler a descrição antes de instalar qualquer coisa. As permissões declaradas são estas:

PermissãoNívelPara quê serve
ContentsSomente leituraClonar o repositório e ler o upuai.toml no build
MetadataSomente leituraNome do repositório, branches, dados básicos
Email addresses (conta)Somente leituraO e-mail verificado usado no login

Metadata não é escolha nossa: o GitHub força leitura de metadata em qualquer App que tenha alguma permissão de repositório. Se você tentar desligá-la mantendo o resto, a própria plataforma religa.

Os eventos que o App assina também são curtos: push, que é o que dispara o deploy automático, e repository, que avisa quando um repositório é renomeado ou transferido para que o seu serviço não pare de deployar em silêncio.

Não há Contents: write. Não há Administration. Não há Pull requests, Checks, Statuses, Deployments, Workflows nem Actions. Se aparecer qualquer linha com “write” nessa tela, algo está errado, e a seção final deste post explica por que isso não pode acontecer sem você aprovar.

O token que chega no build vê um repositório, por uma hora

Permissão declarada é uma coisa. O que efetivamente sai da plataforma e chega na máquina que faz o build é outra, e é onde mora a diferença prática.

Quando o seu deploy é despachado, a Upuai pede ao GitHub um token atenuado: um repositório só, uma permissão só, validade de uma hora. Isso não é configuração de tela, é uma constante no código do produto:

// apps/api/src/lib/github-installation-token.ts
// Permissão mínima para clonar e ler o repositório. Deliberadamente explícita:
// mesmo que o App ganhe permissões novas no futuro, o token que sai da
// plataforma rumo ao cluster continua limitado a leitura de conteúdo.
const BUILD_PERMISSIONS = { contents: 'read' } as const

A API do GitHub aceita restringir o token na hora de emitir, por repositories e por permissions, e a validade é definida pela plataforma deles: “The installation access token will expire after 1 hour”. Compare com o modelo antigo, em que o cluster recebia um token com escrita em todos os repositórios do usuário e sem prazo de expiração.

Duas decisões de engenharia sustentam isso no dia a dia:

  1. O token nunca viaja na fila. O que entra no job de deploy é uma referência (qual instalação, qual repositório), e o token é gerado imediatamente antes do despacho. Não é preciosismo: um build pesado ocupando o slot já passa de uma hora, então um token assado cedo e usado tarde falharia no git clone. O efeito colateral é que o segredo também deixou de existir dentro do Redis.
  2. O token de instalação que a plataforma usa para listar seus repositórios no painel fica cifrado em AES-256-GCM. Cache não é cofre, e esse token abre repositório de cliente.

Tem ainda uma armadilha que não é óbvia e que vale contar. Os identificadores de instalação do GitHub são sequenciais, ou seja, adivinháveis. Aceitar o número cru na volta do fluxo permitiria a alguém vincular ao próprio workspace a instalação de outra empresa e passar a ler o código dela. Por isso o callback troca o código por um token de usuário e confirma com o GitHub que aquela pessoa enxerga aquela instalação antes de gravar qualquer coisa.

O que a permissão mínima nos impede de fazer

Esta é a parte que separa um post honesto de um anúncio. Ler o mínimo tem preço, e o preço é nosso e seu ao mesmo tempo.

1. A Upuai não escreve nada no seu commit nem no seu pull request. Sem Checks e sem Statuses, não existe aquele selo verde de deploy do lado do commit no GitHub, nem comentário automático com a URL do ambiente. O resultado do seu deploy aparece no painel e chega por e-mail, e não ao lado do código. É uma comodidade real que a gente abre mão, e a alternativa seria pedir escrita.

2. A gente não abre pull request e não commita arquivo por você. O upuai.toml, que descreve build e deploy do serviço, vive no seu repositório e é você quem faz o commit. A plataforma lê esse arquivo, nunca o corrige sozinha.

3. A gente não cria nem apaga webhook dentro do seu repositório. Com GitHub App, os eventos chegam pelo webhook do próprio App, então aquele hook que a integração antiga cadastrava (e que continuava lá se você esquecesse de desconectar) deixou de existir.

4. Se o acesso sumir, o deploy para, e a gente não tem rota alternativa. Tirar o repositório da seleção ou suspender a instalação é um botão seu, e ele funciona. O deploy falha com uma mensagem que diz exatamente o que fazer, algo como “o repositório fulano/beltrano não está na seleção da instalação do GitHub App, adicione-o em Configure repositories no GitHub”. Não existe caminho antigo guardado para contornar.

5. Repositório apagado ou arquivado não apaga a sua configuração. Este item não é limite de permissão, é decisão de produto, e ela combina com o resto: quando chega um evento de exclusão ou arquivamento, a plataforma só registra. Repositório pode ser restaurado, e destruir configuração de cliente por causa de um evento externo seria transformar um susto em prejuízo.

O acesso antigo não foi desligado, foi apagado

Migrar a integração resolve o cliente novo. O cliente antigo continuaria com um token de escrita guardado em algum lugar, e é aí que a maioria das migrações para no meio.

O corte foi executado em 30 de julho, nesta ordem: primeiro os avisos por e-mail para os responsáveis dos workspaces que ainda dependiam do modelo antigo, depois a remoção de 35 webhooks legados dos repositórios, a exclusão de 15 conexões e, por último, o DROP TABLE da tabela que guardava esses tokens no banco de produção. A ordem importa: remover o hook usa justamente o token que estava sendo descartado, então apagar a linha primeiro deixaria lixo nosso dentro do repositório do cliente, apontando para um endpoint que passaria a rejeitar a assinatura.

O passivo que motivou a migração inteira não foi desativado. Ele deixou de existir.

Login com GitHub não toca no seu código

Vale separar as duas coisas, porque elas viraram telas diferentes. Entrar na Upuai com GitHub usa os escopos read:user e user:email: perfil e e-mail verificado, nada além disso. Você pode criar conta, olhar a plataforma e nunca autorizar acesso a repositório nenhum.

Dar acesso a código é um segundo passo, explícito, que você faz quando for subir o primeiro serviço, escolhendo os repositórios um a um.

GitLab é diferente, e esconder isso seria propaganda

Se o seu código está no GitLab, o texto acima não se aplica na mesma medida, e essa ressalva precisa estar aqui e não numa nota de rodapé.

A conexão de GitLab da Upuai ainda é OAuth, com os escopos api read_user read_repository. A documentação do GitLab descreve o api assim: “Grants complete read and write access to the API for the token’s scope”. É um escopo amplo, e ele é necessário hoje porque no GitLab o webhook continua sendo criado por projeto, pela plataforma.

Ou seja: no GitHub, a Upuai pede leitura de conteúdo e mais nada. No GitLab, o escopo é maior do que a gente gostaria. Isso é dívida nossa, não característica do seu repositório, e é honesto dizer que quem quiser o modelo de permissão mínima descrito neste post tem ele hoje no caminho GitHub.

Ainda sobre o seu código: o resumo de falha de build

Já que o assunto é o que acontece com o conteúdo do seu repositório, tem mais uma coisa que você deveria saber antes de decidir, e ela está declarada na nossa página de subprocessadores: quando um build falha, a Upuai gera uma explicação em português com causa provável e ação recomendada, e para isso o trecho de log relevante passa por um modelo de linguagem do Google. Esse trecho pode conter um pedaço de código.

Sua aplicação, seus bancos, seus buckets e seus volumes continuam rodando no Brasil. A lista completa de quem trata o quê, e em que país, é pública e versionada, junto com os outros documentos em upuai.com.br/legal. Se você está avaliando isso com o rigor de quem responde por dado pessoal, o checklist de LGPD para times técnicos e o texto sobre soberania digital como gestão de risco contratual tratam do assunto sem romantizar.

Como conferir em dois minutos, e como revogar

Você não precisa acreditar em nenhum parágrafo acima. Dá para auditar do seu lado:

  1. No GitHub, vá em Settings, depois Applications, aba Installed GitHub Apps.
  2. Clique em Configure no Upuai Cloud.
  3. A tela mostra Repository access (todos, ou a lista exata que você marcou) e a seção Permissions, com o nível de cada uma.
  4. Na mesma tela ficam Suspend e Uninstall. Suspender corta o acesso na hora e mantém a configuração; desinstalar apaga a instalação.

Dentro da Upuai, o mesmo estado aparece em Configurações, seção GitHub, com uma frase que a gente colocou lá justamente para não depender deste blog: “A Upuai pede apenas acesso de LEITURA ao código, e somente nos repositórios que você selecionar no GitHub”.

Como a gente garante que isso não volta atrás

Duas travas, uma nossa e uma do GitHub.

A nossa é um verificador que roda contra a API real e falha se aparecer qualquer permissão diferente de leitura no App. Ele também prova a atenuação do token de build, confirmando que o token emitido para um repositório enxerga um repositório, e não a instalação inteira. É um comando, não um documento, então ele envelhece junto com o código.

A do GitHub é mais forte: adicionar permissão a um App não é silencioso. Na documentação deles, “each account where the app is installed will need to approve the new permissions”, e enquanto a aprovação não vem, “updated permissions won’t take effect”. Se um dia a Upuai pedir escrita, você vai ter que clicar em concordar. Remoção de permissão, ao contrário, vale imediatamente.

Perguntas frequentes

A Upuai pode alterar o código do meu repositório? Não pelo GitHub App. As permissões concedidas são de leitura, e o token que roda no build é emitido com contents: read, limitado a um repositório e a uma hora. Sem permissão de escrita, a API do GitHub rejeita qualquer tentativa de escrita, independentemente do que o nosso código tentasse fazer.

Vocês enxergam todos os meus repositórios? Só os que você marcar na instalação. Se você selecionar um repositório, o picker da Upuai vai listar um repositório. Você pode mudar essa seleção quando quiser, sem falar com a gente, e a mudança vale na hora.

Por que o App pede meu endereço de e-mail? Para o login. É o e-mail verificado que identifica a sua conta na plataforma e para onde vão os avisos de deploy. É uma permissão de conta, não de repositório: ela não dá acesso a código nenhum.

Se eu desinstalar o App, perco a configuração dos meus serviços? Não. A configuração do serviço (repositório, branch, build) continua na Upuai. O que acontece é que o deploy passa a falhar com erro explícito até você reinstalar. Ao reinstalar, o serviço volta a funcionar sem reconfigurar nada.

Isso muda alguma coisa para quem faz deploy via CLI ou por imagem Docker? Não muda nada, e é uma alternativa legítima se você prefere não instalar App nenhum. Dá para subir aplicação com o CLI da Upuai ou publicando uma imagem pronta, como mostra o guia de deploy com Dockerfile. O acesso ao repositório existe para o fluxo de git push, não para a plataforma funcionar.

E se o meu código está no GitLab? Aí o modelo é outro, e nada do que está descrito acima vale igual: a conexão de GitLab da Upuai ainda é OAuth, com os escopos api read_user read_repository, e o api dá leitura e escrita na API do GitLab. A permissão mínima deste post existe hoje no caminho GitHub; no GitLab o escopo é maior do que a gente gostaria, e isso é dívida nossa.

O resumo em uma frase

Confiar código-fonte privado a um fornecedor é uma decisão de risco, e a resposta honesta para ela não é uma promessa, é uma tela que você abre e confere sozinho: no GitHub, três linhas de leitura, os repositórios que você escolheu, um token de uma hora.

Se quiser ver o resto da plataforma antes de instalar qualquer coisa, os 15 dias de teste não pedem cartão, e o guia de deploy de Next.js mostra o caminho inteiro do git push até o ar. Comece seus 15 dias grátis, sem cartão.

Faça deploy no Brasil em 5 minutos

PaaS brasileira, preços em Real, infraestrutura LGPD-native.

Ver planos

Artigos relacionados