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>
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:
- https://gitea.fatorxtech.com/cferraz/adaptador-planilhas/actions
- https://gitea.fatorxtech.com/cferraz/adaptador-planilhas/actions/runs/666 (Waiting)
- https://gitea.fatorxtech.com/cferraz/adaptador-planilhas/actions/runs/584 (Canceled)
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 oruns-ondos 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_FILEem vez da variável com o valor: o token não aparece emdocker inspectnem 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 é oruns-ondos três jobs. O mapeamentodocker://node:24-bookwormjá entreganodeenpmna versão certa. psqlepython3não vêm nessa imagem. O jobservicesusapsqle a jornada assíncrona usapython3. Duas saídas: trocar o mapeamento para uma imagem que os tenha, ou deixar que orunner-checkreporte a ausência e então instalá-los num passo do workflow. Rode orunner-checkprimeiro: ele faz esse inventário.- Rede de saída necessária:
gitea.fatorxtech.com(fila e logs),github.com(o Gitea resolveactions/checkout@v4,actions/setup-node@v4edocker/*via proxy),registry.npmjs.orgedocker.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.
runner-check— dispare manualmente. Não faz checkout, não instala nada, não usa segredo. Confirma a ligação e inventarianode,npm,docker,psql,python3.verify— lint, typecheck, 102 testes, build.services— Postgres e Redis efêmeros: as quatro migrations, idempotência,--dry-runsem efeito, shim recusado comADAPTER_APPLY_IDENTITY_SHIM=0,app_usersemBYPASSRLS,FORCE RLS, isolamento entre workspaces, auditoria não alterável.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 exigindoSIGTERM recebidoem 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.