s3lph made – Construindo Pacotes AUR com Forgejo Actions and Renovate
O Arch User Repository (AUR) é uma coleção de pacotes fonte contribuídos pelo usuário para Arch Linux. Esses pacotes, que podem ser enviados por qualquer pessoa sem revisão, consistem simplesmente em metadados de pacotes e instruções para baixar e construir software a partir do código-fonte. Isto também significa que deve-se tomar cuidado especial ao usar pacotes AUR; embora possam ser extremamente úteis, também podem conter malware, como ficou evidente mais uma vez recentemente.
A maneira “recomendada” de construir um pacote AUR é verificar o repositório fonte do pacote, revisar seu conteúdo e então construir o pacote usando o Arch’s makepkg ferramenta de construção de pacotes. Como este pode ser um processo bastante tedioso, existem várias ferramentas auxiliares de construção do AUR diferentes, no entanto, seu uso não é recomendado, pois geralmente causam vários problemas difíceis de solucionar. Tendo sido um usuário de longa data desses auxiliares AUR e enfrentando regularmente os problemas mencionados acima, eu queria encontrar uma solução melhor (e mais fácil) para construir pacotes AUR.
Forgejo ao Resgate!
O git forge Forgejo de código aberto, que também rodamos em nosso hackerspace, vem com um registro de pacote Arch Linux. Este registro pode simplesmente ser adicionado à lista de repositórios de software em uma instalação do Arch Linux /etc/pacman.confe pacotes compilados podem ser enviados para ele por meio de um endpoint da API REST.
Para construir os pacotes AUR necessários, configurei um fluxo de trabalho Forgejo Actions, que constrói esses pacotes pelo menos uma vez por semana ou quando as alterações são enviadas para o repositório:
---
# Build on commits to main and once a week
on:
push:
branches:
- main
schedule:
- cron: "0 6 * * 1" # every Monday at 6 AM
jobs:
# One step per package, for other packages just do `packagename: *job`
sslyze: &job
runs-on: docker
container:
# base-devel is implicitly required for package building.
# Any other dependencies must be declared explicitly.
image: docker.io/library/archlinux:base-devel
env:
# Secrets required to push to the package registry
API_REPOSITORY_ARCH: ${{ secrets.API_REPOSITORY_ARCH }}
API_REPOSITORY_ARCH_DEBUG: ${{ secrets.API_REPOSITORY_ARCH_DEBUG }}
API_USERNAME: ${{ secrets.API_USERNAME }}
API_PASSWORD: ${{ secrets.API_PASSWORD }}
steps:
- name: Prepare build pipeline
run: |
# nodejs and git are needed for the checkout action; unlike the default image,
# `docker.io/library/ubuntu`, these are not shipped by default in `archlinux:base-devel`.
pacman --noconfirm -Sy nodejs git
- name: Checkout repository
# This only checks out the project repo, not the submodules
uses: https://code.forgejo.org/actions/checkout@v7
- name: Build and upload package
run: |
# Add AUR repo itself for makedepends from AUR
curl https://git.kabelsalat.ch/api/packages/s3lph/arch/repository.key > /sign.gpg
pacman-key --init
pacman-key --add /sign.gpg
pacman-key --lsign-key 's3lph@noreply.git.kabelsalat.ch'
cat >> /etc/pacman.conf
(aur)
SigLevel = Required
Server = https://git.kabelsalat.ch/api/packages/s3lph/arch/aur/\$arch
EOF
pacman -Sy
# Checkout only the submodule of the package to build in this job
git submodule update --init "${FORGEJO_JOB}"
chown nobody: -R "${FORGEJO_JOB}" && cd "${FORGEJO_JOB}"
# Check if the PKGBUILD contains run-time or compile-time dependencies, and install if necessary
(source ./PKGBUILD && (( -n "${depends(@)}${makedepends(@)}" )) && pacman --noconfirm -S ${depends(@)} ${makedepends(@)} || true)
# Build the binary package(s) from this source package
sudo -E -u nobody -- makepkg --cleanbuild
# All debug packages are uploaded to the separate aur-debug registry
for file in *-debug-*pkg.tar*; do
curl -X PUT "${API_REPOSITORY_ARCH_DEBUG}" \
--user "${API_USERNAME}:${API_PASSWORD}" \
--header "Content-Type: application/octet-stream" \
--data-binary @"${file}" || true
done
rm -f *-debug-*pkg.tar*
# The regular packages are uploaded to the `aur` registry
for file in *pkg.tar*; do
curl -X PUT "${API_REPOSITORY_ARCH}" \
--user "${API_USERNAME}:${API_PASSWORD}" \
--header "Content-Type: application/octet-stream" \
--data-binary @"${file}"
done
Atualizando Pacotes com Renovate
Portanto, agora tenho um pipeline que cria os pacotes AUR necessários regularmente e um repositório para onde esses pacotes são enviados. No entanto, ainda tenho o problema de revisar todas as alterações nos pacotes AUR para garantir que nenhum código malicioso seja introduzido.
Para resolver isso, adicionei todos os repositórios de pacotes AUR necessários ao meu repositório de pipeline como submódulos git. Esses submódulos são fixados em um ID de commit fixo do git, portanto, não estou extraindo as alterações mais recentes não revisadas, mas sempre construo um pacote para o qual sei que revisei as instruções de construção.
Para receber atualizações desses submódulos, estou usando a ferramenta de gerenciamento de dependências Renovate, que é executada como outro fluxo de trabalho do Forgejo Actions em outro repositório no mesmo servidor Forgejo. Uma vez por dia, o Renovate verifica se há algum tipo de atualização de dependência que precisaria ser aplicada aos repositórios que monitora. Entre muitos outros tipos de dependências, o Renovate também suporta a verificação se o commit para o qual um submódulo git aponta ainda é o commit upstream mais recente. Se alguma dependência “desatualizada” for encontrada, o Renovate abre uma solicitação pull no repositório e a atribui ao proprietário para revisão.
No entanto, essas solicitações pull consistem apenas em um ID de commit de submódulo alterado, portanto, a revisão das alterações reais não é tão trivial:
--- a/sslyze
+++ b/sslyze
@@ -1 +1 @@
-Subproject commit 848023a5347b8af959de3287d65eb12b0fc341e2
+Subproject commit d78430b2aad33c00ca047f4f498d61ef9a25566e
A última peça do quebra-cabeça é outro fluxo de trabalho do Forgejo Actions, que é acionado por estas solicitações pull:
---
# Run whenever a PR is opened or changed
on:
pull_request:
types:
- opened
- synchronize
- reopened
jobs:
diff:
runs-on: docker
steps:
- name: Checkout repository
uses: https://code.forgejo.org/actions/checkout@v6
with:
submodules: true
fetch-depth: 0
- name: Compute diff and post comment
run: |
apt update; apt install --yes python3-all
# the comment.py script just posts the output of `git diff --submodule=diff`
# as a comment to the PR, or updates an existing comment.
python3 .forgejo/comment.py
Este fluxo de trabalho verifica o repositório do pipeline, incluindo todos os submódulos, e calcula a diferença de PR, incluindo os submódulos. A comparação resultante é então postada como um comentário na solicitação pull, o que me permite revisar facilmente as alterações:
Figura 1: Captura de tela de uma comparação comentada em uma solicitação pull pelo Forgejo Actions
