name: CI # Documentação e configuração de ferramenta não mudam nada que a suíte teste. # Na main não roda por push: o release.yml é quem a chama, e só quando a imagem # precisa ser reconstruída; rodar nos dois repetiria a mesma suíte no mesmo commit. # Sem gatilho de pull_request: o push da branch já valida o mesmo commit, e os # dois juntos rodariam tudo duas vezes (o repositório não recebe PR de fork). # # A imagem é construída aqui uma única vez, em arm64 (a arquitetura do servidor), # testada e publicada como inputs-. Ao fazer o merge, o release encontra # essa tag e só aplica os nomes novos, sem rodar nem construir nada de novo. on: push: branches-ignore: [main] paths-ignore: ['**.md', 'LICENSE', 'CITATION.cff', 'paper.md', 'references.bib', 'docs/**', '.claude/**', '.wolf/**', '.superset/**', 'scripts/release-notes.sh'] schedule: - cron: '0 9 * * 1' # toda segunda: reavalia com a base de vulnerabilidades nova workflow_call: permissions: contents: read concurrency: group: ci-${{ gitea.ref }} cancel-in-progress: true jobs: verificar: name: Tipos e testes runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: npm - run: npm ci # tsc -b é o mesmo que o build faz antes do Vite; aqui falha antes de gastar a imagem. - run: npx tsc -b - run: npm test # Trivy roda pela imagem oficial: o trivy-action clona o repositório do Trivy # do mesmo servidor do workflow, que aqui é o Gitea, e não o GitHub. # O workspace do job é um volume que o daemon não enxerga, então os arquivos # entram no container com `docker cp` em vez de `-v`. seguranca: name: Trivy (dependências e segredos) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Repositório run: | cid=$(docker create --network host -v trivy-cache:/root/.cache/ -w /src aquasec/trivy:0.70.0 \ fs --scanners vuln,secret,misconfig --severity HIGH,CRITICAL --exit-code 1 .) docker cp . "$cid:/src" docker start -a "$cid" status=$(docker inspect -f '{{.State.ExitCode}}' "$cid") docker rm "$cid" >/dev/null exit "$status" # Só começa depois das verificações baratas: um teste quebrado não gasta um # build de imagem. Roda no runner arm64, o mesmo tipo do servidor, então o # que é escaneado e testado é a imagem que vai ao ar. imagem: name: Imagem Docker (linux/arm64) needs: [verificar, seguranca] runs-on: ubuntu-24.04-arm env: REGISTRY: git.lucasrguerra.dev.br steps: - uses: actions/checkout@v4 # Conteúdo já publicado (re-push, tag num commit já validado): nada a fazer. - id: plano run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT" - if: ${{ steps.plano.outputs.reuse != 'true' }} uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ gitea.actor }} password: ${{ secrets.REGISTRY_TOKEN }} # `docker build` simples, no daemon persistente do runner: as camadas e o # cache mount do npm sobrevivem entre execuções. Um buildx criaria um # BuildKit novo, e vazio, a cada job. - name: Build if: ${{ steps.plano.outputs.reuse != 'true' }} run: docker build -t pss:ci . - name: Trivy na imagem if: ${{ steps.plano.outputs.reuse != 'true' }} run: | docker run --rm --network host -v trivy-cache:/root/.cache/ -e DOCKER_HOST=tcp://127.0.0.1:2375 aquasec/trivy:0.70.0 \ image --severity HIGH,CRITICAL --exit-code 1 pss:ci # A SPA sobe, cai no index nas rotas internas e entrega os assets com # cache imutável (scripts/smoke-imagem.sh). - name: A imagem sobe e responde if: ${{ steps.plano.outputs.reuse != 'true' }} run: | docker run -d --name pss-ci -p 127.0.0.1:3998:8080 pss:ci status=0 scripts/smoke-imagem.sh http://127.0.0.1:3998 || status=1 docker rm -f pss-ci >/dev/null exit "$status" # Passou em tudo: publica a mesma imagem que foi testada, sem reconstruir. - name: Publica inputs- if: ${{ steps.plano.outputs.reuse != 'true' }} run: | tag="${{ steps.plano.outputs.image }}:inputs-${{ steps.plano.outputs.inputs }}" docker tag pss:ci "$tag" docker push "$tag"