Skip to content

Repository files navigation

CapivaDeploy — Ambientes Efêmeros de QA

CapivApp

Sobe ambientes temporários isolados a partir de qualquer branch/commit do GitLab, para o setor de Qualidade testar sem depender de Dev ou Infra.

Cada ambiente recebe container próprio, banco próprio (restaurado de backup ou copiado de produção/homologação), URL única com HTTPS (DNS no Pi-hole + Traefik), prazo de validade com renovação, remoção automática e auditoria completa.

Faz parte da família Capiva* da CapivApp e herda a identidade da marca (mascote, índigo #6366F1 → magenta #EC4899).

Documentação detalhada em /doc · progresso em TODO.md.


Como rodar

bun install
bun run infra:up        # Postgres + Traefik + Pi-hole (docker compose)
bun run prisma:generate
bun run seed            # cria o admin (ADMIN_EMAIL / ADMIN_PASSWORD)
bun run dev:all         # API (3000) + worker + web (5173)

Processos separados, se preferir: bun run dev (API), bun run worker (fila e crons), bun run dev:web (frontend).


Fluxo do QA

  1. Projeto → branch → commit (navegação pela API do GitLab, com autor, data e mensagem do commit).
  2. Dockerfile e porta do build (repositórios com vários Dockerfiles).
  3. Origem do banco: upload .sql/.sql.gz, backup salvo, cópia de produção ou cópia de homologação.
  4. Dependências: as variáveis liberadas pelo admin. As do tipo url trazem um seletor dos ambientes já no ar — o QA aponta o front para o back sem digitar endereço (ver abaixo).
  5. Deploy — o pipeline provisiona tudo e publica a URL.

Dependências entre ambientes

Um front precisa saber a URL do back. Para isso:

  • O admin cadastra a variável no projeto (ex.: VITE_API_BASE_URL) marcando o tipo URL (dependência) e, se quiser, um valor padrão e a obrigatoriedade.
  • O QA, ao criar o ambiente, vê essa variável na seção Dependências e escolhe num select o ambiente de destino: a URL é preenchida sozinha. Digitar à mão continua possível.
  • Variáveis cujo nome sugere endereço (*_URL, *_URI, *_ENDPOINT, *_HOST, API_BASE*…) ganham o seletor mesmo sem o tipo declarado.
  • Depois de criado, o botão Dependências no card do ambiente permite corrigir as URLs e refazer o deploy num passo só.

Obrigatórias em branco e URLs mal formadas bloqueiam o deploy no formulário, com o motivo ao lado do campo.

Variáveis de build × de runtime

Cada variável do projeto declara quando vale — no cadastro e na edição:

Escopo Vai para Use quando
Build + runtime (padrão) --build-arg e env do container quase tudo
Só no build --build-arg a imagem precisa em tempo de build (migrations, bundle)
Só no runtime env do container só o processo em execução usa

A variável do banco é tratada automaticamente, e essa é a razão de o recurso existir: quando o projeto define um usuário de aplicação (RLS), o build recebe a URL do usuário administrativo — dono das tabelas, exigido pelo prisma migrate deploy — e o container recebe a do usuário de aplicação, sujeito a RLS. Com um mapa único de variáveis, o build herdava a URL do usuário de aplicação e a migration quebrava com must be owner of table. É a mesma separação que os Dockerfiles fazem entre MIGRATION_DATABASE_URL e DATABASE_URL.


Ações no ambiente

Ação O que faz
Reiniciar Reinicia só o container. Banco, imagem, rede e DNS intactos.
Refazer deploy Roda o pipeline do zero — recria o banco a partir da origem. Pede confirmação.
Renovar Estende a validade, respeitando prazo máximo e limite de renovações.
Dependências Edita as variáveis autorizadas; opcionalmente já refaz o deploy.
Progresso/Logs/Console SSE do pipeline, logs do container e shell interativo (xterm).
Excluir Remove container, banco, volume, rede e registro DNS. Pede confirmação.

Reiniciar e refazer deploy eram a mesma operação destrutiva antes; hoje são separadas, para o QA não perder os dados de teste ao reiniciar a aplicação.


Servidores de deploy (Docker/Podman, local ou remoto)

Os ambientes não precisam rodar na mesma máquina do CapivaDeploy. Em Configurações → Servidores de deploy (ADMIN) cadastra-se cada alvo:

Campo Para que serve
Runtime Docker ou Podman — ambos falam a mesma Engine API.
Conexão Local (socket do próprio host) ou Remoto (SSH).
IP / porta / usuário Endereço do servidor remoto.
Chave SSH privada Chave sem passphrase com acesso ao engine. Guardada no banco e nunca devolvida pela API.
Socket Opcional. Vazio = padrão do runtime (Docker /var/run/docker.sock, Podman /run/podman/podman.sock).
Padrão Usado por projetos que não escolheram servidor.

O botão Testar faz o handshake real com o engine (pede a versão) — é o jeito de validar IP, chave e socket antes do primeiro deploy.

No cadastro do projeto, o campo Servidor de deploy escolhe o alvo. O servidor é congelado no ambiente no momento da criação: logs, console, reinício e remoção continuam mirando o engine onde ele subiu, mesmo que o projeto passe a apontar para outro servidor depois.

Como funciona por dentro

  • Docker e Podman compartilham o mesmo adapter (DockerService): o Podman expõe uma Engine API compatível, então não há um segundo cliente.
  • Para SSH, a Engine API trafega dentro da sessão SSH e é exposta como um socket unix local (@modules/container/sshSocketBridge) — do ponto de vista do dockerode não há diferença para o caso local.
  • Duas razões para a ponte, em vez de um http.Agent customizado (o caminho que o próprio dockerode usa):
    1. O Bun não invoca agent.createConnection; o Node invoca. Como a API e o worker rodam em Bun, um agente customizado é silenciosamente ignorado e o cliente acaba fazendo HTTP puro contra a porta 22.
    2. O transporte SSH do dockerode fixa docker system dial-stdio; na ponte o comando é parâmetro, então Podman remoto funciona sem o shim podman-docker no servidor.
  • A ponte bufferiza o início da requisição: o canal SSH só abre depois do handshake (~1s), e o Bun descarta o que chega num socket antes de existir um leitor (o Node bufferiza). Sem isso a requisição se perde e a conexão fica pendurada. As duas peculiaridades do Bun estão fixadas em sshSocketBridge.test.ts — se algum dia mudarem, os testes quebram e a ponte pode ser simplificada.
  • A seleção "qual cliente para qual servidor" vive numa única Factory (ContainerOrchestratorFactory) + strategy map por tipo de conexão; steps, workers e rotas só pedem o alvo.

Pré-requisitos no servidor remoto

# Docker: o usuário SSH precisa estar no grupo docker
sudo usermod -aG docker deploy

# Podman: habilitar o socket do serviço
sudo systemctl enable --now podman.socket
# rootless: /run/user/<uid>/podman/podman.sock — informe em "Socket" no cadastro

Postgres efêmero continua central. Os bancos dos ambientes seguem sendo criados no servidor Postgres do CapivaDeploy (EPHEMERAL_PG_*) — o servidor de deploy precisa alcançá-lo pela rede. Isso mantém pg_dump/psql e os backups num lugar só; o que passa a ser remoto é o build e a execução do container.


Controle de acesso

Papel Pode
Administrador Tudo: projetos, variáveis, prazos, configurações, backups, qualquer ambiente.
QA Criar, renovar, reiniciar, editar dependências e excluir os ambientes próprios.
Visualizador Somente leitura.

Configurações e Backups são exclusivas do admin — na API (403) e no menu. Token do GitLab e URLs de banco de produção/homologação não são enviados a QA/Visualizador; o token nunca é reexibido na edição do projeto (em branco = manter o atual).


Nomenclatura dos recursos

Os recursos de um ambiente derivam de env-<projeto>-<hash>:

container  env-siart-web-front-3607143
rede       net-env-siart-web-front-3607143
banco      db_env_siart_web_front_3607143
imagem     env-siart-web-front-3607143:latest

O projeto entra no nome porque o mesmo commit pode ser deployado por dois projetos diferentes (repositório único com Dockerfiles de front e back). Sem isso, o segundo deploy removeria o container e o banco do primeiro.


Endpoints principais

POST   /api/environments                 cria (enfileira deploy)
PUT    /api/environments/:id/variables   edita as dependências
POST   /api/environments/:id/restart     reinicia o container
POST   /api/environments/:id/redeploy    refaz o pipeline (recria o banco)
POST   /api/environments/:id/renew       renova a validade
DELETE /api/environments/:id             remove o ambiente
GET    /api/environments/:id/deploy/stream   progresso do deploy (SSE)
GET    /api/environments/:id/logs/stream     logs do container (SSE)

POST   /api/projects/:id/variables       cadastra/edita variável (upsert por chave)
DELETE /api/projects/:id/variables/:key  remove variável
GET|PUT /api/settings                    configurações do sistema (ADMIN)

GET    /api/servers                      lista os servidores de deploy (ADMIN)
POST   /api/servers                      cadastra servidor (ADMIN)
PUT    /api/servers/:id                  edita servidor — chave em branco = manter (ADMIN)
POST   /api/servers/:id/test             handshake com o engine do servidor (ADMIN)
DELETE /api/servers/:id                  remove servidor (ADMIN)

Diagnóstico

"As branches não carregam ao escolher o projeto"

Quase sempre é o token do GitLab (Configurações → GitLab). A tela mostra o motivo exato devolvido pelo GitLab logo abaixo do campo:

Mensagem O que fazer
Token inválido ou revogado Gere um novo PAT no GitLab e cole em Configurações.
Token sem permissão para este projeto O PAT precisa dos escopos read_api e read_repository.
Projeto não encontrado Confira o "ID do projeto GitLab" no cadastro do projeto.
Não foi possível falar com o GitLab Rede/DNS/URL base — teste a URL base a partir do servidor.

O PAT precisa de dois escopos: read_api (navegação pela API) e read_repository (o clone durante o deploy). Só read_repository faz toda a navegação falhar com 403 — ele libera apenas git clone, não a API REST.

Teste o token direto contra o servidor:

curl -s -o /dev/null -w '%{http_code}\n' \
  -H "PRIVATE-TOKEN: <seu-token>" https://<seu-gitlab>/api/v4/user
# 200 = válido · 401 = inválido/revogado

Falhas de dependência externa respondem 502 (não 401), justamente para não serem confundidas com "sua sessão expirou" — o cliente rotacionaria o refresh token à toa.

Stack

BunJS · TypeScript · Express 5 · Prisma 7 · PostgreSQL · fila em SQLite (bun:sqlite, sem Redis) · Docker ou Podman, local ou remoto por SSH · Traefik · Pi-hole · React + Vite + TailwindCSS + TanStack Query.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages