Files
adaptador-planilhas/docs/spreadsheet-adapter/22-gitea-actions.md
T
camilafagundesandClaude Opus 5 c5790ab301
ci / lint, typecheck, testes e build (push) Has been cancelled
ci / Postgres e Redis reais (push) Has been cancelled
ci / imagem Docker Linux (push) Has been cancelled
runner-check / o runner responde (push) Has been cancelled
Protege o CI em repositório público e prepara a ativação do runner
O push para o Gitea criou o run, mas ele ficou em Waiting: a mensagem da
instância é "No matching online runner with label: ubuntu-latest". A falha é na
atribuição do job, não no enfileiramento — o gatilho funcionou e a branch está
contemplada. O endpoint /actions/tasks devolvia lista vazia porque lista tasks
aceitas por runner, não runs criados, e foi isso que confundiu a leitura.

Com o diagnóstico fechado, duas coisas importam antes de um runner existir.

Primeira: este repositório é público e o CI dispara em pull_request. Sem
guarda, um fork traria código de terceiro para rodar na máquina do runner, com
Docker à disposição. Os três jobs do ci.yml e o runner-check passam a exigir
que o PR venha da própria origem; push continua rodando normalmente. Também
entram `permissions: contents: read` e `concurrency` por ref, para não
acumular fila de runs esperando runner.

Segunda: `runner-check` é o primeiro workflow a rodar quando o runner subir.
Não faz checkout, não instala dependência, não usa segredo e não toca rede
externa. Só confirma a ligação e inventaria node, npm, docker, psql e python3
— o job `services` precisa de psql e a jornada assíncrona precisa de python3,
e é melhor descobrir isso num workflow de dez segundos.

A documentação registra a evidência (runs 666 em Waiting e 584 cancelado),
recomenda act_runner 0.6.1-dind-rootless com escopo de repositório, e explica
por que Docker-in-Docker em vez do socket do host: num repositório público,
montar o socket entregaria o Docker da máquina ao workflow. Fica registrado
também que os ambientes de aprovação manual do deploy são conceito do GitHub e
não têm equivalente no Gitea.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-15 21:17:12 -03:00

8.4 KiB

Gitea Actions — diagnóstico e ativação do runner

Repositório cferraz/adaptador-planilhas em gitea.fatorxtech.com, Gitea 1.26.2.

Causa confirmada da ausência de execuções

Os runs existem. O que não existe é runner para executá-los. A falha está na atribuição, não no enfileiramento.

Evidência Resultado
ci.yml detectado por Gitea sim, listado em Workflows
Gatilho de ci.yml on: push sem filtro de branch — contempla homologacao
Actions no repositório habilitado (has_actions: true)
Actions na instância habilitado (a página /actions responde e lista workflows)
Run criado pelo push sim — ci.yml #2, run 666, commit 5b11496cd9, branch homologacao, 2026-10-16 00:05:18 +00:00
Estado do run Waiting, duração 0s
Mensagem do Gitea No matching online runner with label: ubuntu-latest
Run anterior ci.yml #1, run 584, commit 419325db12, branch main — Canceled

Links:

Por que a API parecia dizer "zero execuções"

GET /api/v1/repos/cferraz/adaptador-planilhas/actions/tasks devolve {"workflow_runs":[],"total_count":0}. Esse endpoint lista tasks, isto é, jobs que um runner aceitou. Nenhum runner aceitou nada, então a lista é vazia — mas os runs estão criados e esperando. GET /actions/runs responde token is required, e foi por isso que a primeira leitura passou a impressão errada.

Consequência prática: nada precisa ser republicado. O run 666 está em Waiting e começa sozinho no momento em que um runner com a label compatível ficar online.

Runners encontrados e labels

Runners com label ubuntu-latest online nenhum (é o que o Gitea reporta)
Outros runners na instância não determinado

Listar runners exige token de owner ou admin: GET /api/v1/repos/{owner}/{repo}/actions/runners, ou a interface em Settings → Actions → Runners (nível repositório, organização ou admin). Os números de run (584, 666) sugerem que a instância já teve atividade de Actions em outros repositórios, então é possível que existam runners com outra label. Confira antes de instalar um novo:

  • se já houver runner Linux com Docker e outra label (linux_amd64, ubuntu-22.04, docker), não instale nada: basta ajustar o runs-on dos workflows. Diga qual é a label e a troca é de uma linha em três arquivos;
  • se não houver, siga a instalação abaixo.

Configuração recomendada do runner

Máquina Linux dedicada a homologação, sem nenhuma relação com o Docker de produção do Elo Pro.

Por que Docker-in-Docker, e não o socket do host

O repositório é público. Montar /var/run/docker.sock do host dá ao workflow controle do Docker da máquina — e, num repositório público, código de terceiro poderia chegar lá por pull request de fork. A imagem -dind-rootless sobe um Docker próprio dentro do contêiner do runner: o job image constrói e executa contêineres sem alcançar o Docker do host.

Instalação

Versão fixada, compatível com o Gitea 1.26.2 (0.6.1 é a mais recente publicada; as alternativas semver são 0.1.4 a 0.6.1):

# 1. Token de registro: Settings → Actions → Runners → Create new runner,
#    no NÍVEL DO REPOSITÓRIO (escopo restrito, não use token de admin).
#    Grave o token num arquivo com permissão 600 — nunca em commit, nunca em log.
umask 077
printf '%s' 'COLE_O_TOKEN_AQUI' > /etc/gitea-runner.token

# 2. Suba o runner com Docker-in-Docker rootless.
docker run -d \
  --name gitea-runner-hml \
  --restart always \
  --privileged \
  -e GITEA_INSTANCE_URL=https://gitea.fatorxtech.com \
  -e GITEA_RUNNER_REGISTRATION_TOKEN_FILE=/run/secrets/token \
  -e GITEA_RUNNER_NAME=hml-adaptador \
  -e GITEA_RUNNER_LABELS='ubuntu-latest:docker://node:24-bookworm' \
  -v /etc/gitea-runner.token:/run/secrets/token:ro \
  -v gitea-runner-hml-data:/data \
  docker.io/gitea/act_runner:0.6.1-dind-rootless

Notas que importam:

  • GITEA_RUNNER_REGISTRATION_TOKEN_FILE em vez da variável com o valor: o token não aparece em docker inspect nem no histórico do shell.
  • --privileged é exigência do Docker-in-Docker. É justamente por isso que a máquina precisa ser dedicada.
  • A label tem de ser ubuntu-latest, que é o runs-on dos três jobs. O mapeamento docker://node:24-bookworm já entrega node e npm na versão certa.
  • psql e python3 não vêm nessa imagem. O job services usa psql e a jornada assíncrona usa python3. Duas saídas: trocar o mapeamento para uma imagem que os tenha, ou deixar que o runner-check reporte a ausência e então instalá-los num passo do workflow. Rode o runner-check primeiro: ele faz esse inventário.
  • Rede de saída necessária: gitea.fatorxtech.com (fila e logs), github.com (o Gitea resolve actions/checkout@v4, actions/setup-node@v4 e docker/* via proxy), registry.npmjs.org e docker.io.

Conferir que subiu

docker logs -f gitea-runner-hml        # espere "runner registered successfully"

Depois, em Settings → Actions → Runners, o runner aparece online com a label ubuntu-latest. O run 666, que está em Waiting, começa sozinho.

Ordem de validação

Nenhum destes foi executado ainda. Não marque nada como aprovado sem o log.

  1. runner-check — dispare manualmente. Não faz checkout, não instala nada, não usa segredo. Confirma a ligação e inventaria node, npm, docker, psql, python3.
  2. verify — lint, typecheck, 102 testes, build.
  3. services — Postgres e Redis efêmeros: as quatro migrations, idempotência, --dry-run sem efeito, shim recusado com ADAPTER_APPLY_IDENTITY_SHIM=0, app_user sem BYPASSRLS, FORCE RLS, isolamento entre workspaces, auditoria não alterável.
  4. image — build Linux, conteúdo da imagem, usuário não-root, ausência de .env/docs/testes, os oito scripts operacionais transformando e executando, fail-fast com código diferente de zero na web e no worker, liveness com cabeçalhos, compose até ready, heartbeat do worker, jornada assíncrona entre processos e desligamento gracioso exigindo SIGTERM recebido em menos de 25 s.

Segurança revisada

Risco Estado
Repositório público com Actions ci.yml, runner-check e os três jobs têm guarda: PR de fork não executa (head.repo.full_name == github.repository). Push continua rodando
Código não confiável com acesso privilegiado O runner usa Docker-in-Docker rootless, sem o socket do host. A máquina é dedicada e não alcança o Docker de produção
Deploy automático deploy-staging.yml tem gatilho único workflow_dispatch. Nenhum push, tag ou merge dispara deploy
Aprovação manual de deploy Os ambientes hml-migracao, hml-deploy e hml-flag são conceito do GitHub. O Gitea não os implementa da mesma forma: se o deploy for rodar aqui, as aprovações deixam de existir e isso precisa ser resolvido antes de apontar o workflow ao servidor
Permissão do token de Actions permissions: contents: read nos dois workflows
Fila de runs esperando runner concurrency por ref, com cancelamento do anterior
SSH de produção não configurado. Nenhum segredo de produção foi adicionado
Branch main preservada em 419325d
Token de registro do runner por arquivo com permissão 600, fora de commit e de log

Vale decidir também se este repositório deve seguir público. Auditei os commits e não há segredo algum — só modelos com campos vazios — mas um repositório privado remove de uma vez o risco de PR de fork.

Pendências

Para o CI rodar: um runner Linux online com a label ubuntu-latest, Docker-in-Docker e saída de rede. Nada além disso.

Para homologação, depois do CI verde: projeto Supabase de homologação com contas de teste e bucket privado; DATABASE_URL e a decisão do ADAPTER_APPLY_IDENTITY_SHIM; Redis com senha; DSN do Sentry; DNS, TLS e Nginx de hml-ada.elopro.app; smoke real e ensaio de rollback. O procedimento está em 20-homologacao-runbook.md e o estado item a item em 21-checklist-validacao.md.