AUR
Elke push naar master werkt packaging/aur/PKGBUILD bij en pusht die naar ssh://aur@aur.archlinux.org/bluegit.git (branch master; AUR accepteert niets anders). De aanpak en de geheimnamen zijn dezelfde als in Posprint. Posprint publiceert bij een tag; BlueGit doet het bij elke commit op master, omdat er geen vaste versietag is.
Package
Er is één source-package, bluegit. Geen -bin. De PKGBUILD haalt het archief van BlueGit op, op de commit-sha:
https://git.timfalken.com/timfa/bluegit/-/archive/<commit>/bluegit-<commit>.tar.gz
Die map heet bluegit-<commit>. pkgver is YYYYMMDDHHMMSS, de UTC-committertijd van de commit. De CI-job neemt CI_COMMIT_TIMESTAMP (ISO 8601). Ontbreekt die, dan neemt publish-aur.sh git show -s --format=%cI en rekent die om naar UTC. Het lokale script en de self-updater gebruiken dezelfde committer-tijd, zodat dezelfde sha dezelfde pkgver houdt. pkgrel gaat terug naar 1. _commit is de volledige sha. Het CI-script vult sha256sums met de hash van dat archief. Het lokale script doet hetzelfde met updpkgsums. Beide maken .SRCINFO opnieuw met makepkg --printsrcinfo. Draait de CI-job als root, dan doet gebruiker aurbuild dat (AUR_MAKEPKG_USER overschrijft de naam). De gedeelde functies staan in scripts/aur-common.sh.
De lokale packaging/arch/PKGBUILD blijft voor een build uit de werkboom. Die gaat niet naar de AUR.
Unit en install-hook
De unit is de bestaande system-unit: User=bluegit, ExecStart met /etc/bluegit/config.yml, StateDirectory=bluegit voor /var/lib/bluegit. Geen systemd --user-unit.
packaging/aur/bluegit.install maakt bij installatie en upgrade de systeemgebruiker en de state-map aan. post_install doet systemctl daemon-reload en daarna systemctl enable --now bluegit.service, maar alleen als /etc/bluegit/config.yml er al is én het clientgeheim in /etc/bluegit/client_secret of als BLUEGIT_AUTH_CLIENT_SECRET in /etc/bluegit/secret.env staat. Een lege client_secret: "" telt niet. Ontbreekt een van beide, dan print de hook de vervolgstappen en start hij niets. post_upgrade herlaadt systemd en doet systemctl try-restart bluegit.service. pre_remove doet systemctl disable --now bluegit.service. Draait systemd niet (chroot of container), dan slaat de hook die stappen over zonder fout. backup=('etc/bluegit/config.yml') laat een aangepaste config staan.
De huidige user-unit (/home/timfa/bluegit/config.yml, /home/timfa/bluegit/state, datadisk /home/timfa/temp-bluegit) gaat over naar deze system-service volgens MIGRATIE.md. De datadisk verhuist naar /srv/bluegit; een pad onder /home blijft met ProtectHome=true onbereikbaar. De schijf, het clientgeheim en de ingress van deze installatie staan in BEHEER.md.
Geheimen
De namen zijn 1-op-1 dezelfde als in Posprint. De publieke sleutel hoort op aur.archlinux.org, nooit de private sleutel in de repository.
GitLab (overgang)
.gitlab-ci.yml blijft de pipeline op gitlab.com. Zet daar deze CI/CD-variabelen:
| Naam | Soort | Inhoud |
|---|---|---|
AUR_SSH_PRIVATE_KEY | File, mask uit, protected mag | ruwe OpenSSH-sleutel (BEGIN … PRIVATE KEY). Een File met base64 wordt ook herkend. |
AUR_SSH_PRIVATE_KEY_B64 | Variable, één regel, Masked+Protected | base64 van die sleutel. GitLab maskeert geen meerregelige waarde, daarom base64 of een File. |
AUR_GIT_AUTHOR_NAME | Variable | naam in de AUR-commit |
AUR_GIT_AUTHOR_EMAIL | Variable | e-mail in de AUR-commit |
Eén van de twee sleutelvariabelen is genoeg. scripts/aur-ssh-setup.sh haalt CRLF weg en controleert de sleutel met ssh-keygen -y zonder hem te printen.
De job heet publish:aur. Hij draait alleen als CI_COMMIT_BRANCH master is, met allow_failure: true.
BlueGit
Steve leest blue-ci-cd.yml op de mirror https://git.timfalken.com/timfa/bluegit. Zet dezelfde namen als geheimen op die repository, of op de groep als de repository van een groep is. Eerst de groep, daarna de repository; dezelfde naam laat de repository winnen. BlueGit heeft geen File-type: de waarde van het geheim is de tekst zelf. Een ruwe sleutel in AUR_SSH_PRIVATE_KEY herkent het script aan BEGIN … PRIVATE KEY. Een base64-waarde mag in AUR_SSH_PRIVATE_KEY of in AUR_SSH_PRIVATE_KEY_B64.
Markeer de geheimen als beschermd en bescherm de branch master. Een beschermd geheim komt alleen mee als de branch of tag op een beschermd patroon past.
| Naam | Waarde |
|---|---|
AUR_SSH_PRIVATE_KEY | ruwe OpenSSH-sleutel, of base64 daarvan. Eén sleutelgeheim is genoeg. |
AUR_SSH_PRIVATE_KEY_B64 | dezelfde sleutel als één regel base64. |
AUR_GIT_AUTHOR_NAME | naam in de AUR-commit |
AUR_GIT_AUTHOR_EMAIL | e-mail in de AUR-commit |
BLUEGIT_UPDATE_TOKEN | dezelfde waarde als BLUEGIT_UPDATE_TOKEN in /etc/bluegit/env op de mini-PC |
publish_aur draait op master en main, vóór self_update, met allow_failure: true en needs: [build]. De archive-route staat live, dus de tarball van CI_COMMIT_SHA is te downloaden met de binary die al draait. Een AUR-storing maakt de pipeline niet rood en houdt self_update niet tegen. Een merge-request-pipeline slaat hem over.
Een release die de archive-route zelf wijzigt, kan publish_aur één keer laten falen. Die job draait nog tegen de oude binary. self_update installeert daarna de nieuwe route. Een retry van alleen publish_aur publiceert dan alsnog.
self_update is de laatste job in dezelfde stage en wacht op publish_aur. Omdat die job allow_failure: true heeft, start de deploy ook als de AUR-publicatie mislukt. scripts/self-update.sh stuurt de sha naar POST /api/v1/admin/self-update en stopt meteen, groen. Er is geen poll. De POST antwoordt 202 zodra de unit start. Steve draait in bluegit.service, en post_upgrade herstart die service. Een job die op dat moment nog running is, sterft mee en blijft anders voor altijd op running staan.
CI_API_URL eindigt op /api/v1. De body mag ref zijn; de job stuurt de sha van de pipeline. Zonder BLUEGIT_UPDATE_TOKEN op de server antwoordt het endpoint met 404 en faalt de job. Een merge-request-pipeline draait deze job niet: alleen vet, test, frontend_checks en build.
Lokaal publiceren
Zolang de CI-runner er niet is, publiceert scripts/aur-publish-local.sh met de hand vanuit een lokale checkout. Het gebruikt de AUR-sleutel in ~/.ssh of ssh-agent, en geen CI-variabelen.
De checkout moet op master staan, schoon zijn en gelijk aan origin/master. Het script publiceert de sha van origin/master. Staat die sha al als _commit in de AUR-PKGBUILD, dan stopt het zonder iets te wijzigen.
Het clonet of werkt ssh://aur@aur.archlinux.org/bluegit.git bij in ~/.cache/bluegit-aur (BLUEGIT_AUR_CACHE wijzigt die map), kopieert packaging/aur/*, zet _commit en pkgver, en draait updpkgsums en makepkg --printsrcinfo. Daarna commit het upstream <pkgver> en pusht het naar master. updpkgsums komt uit pacman-contrib.
Self-update
publish_aur wacht op build en publiceert de tarball van deze sha. Die URL werkt op de binary die al draait. self_update wacht op die job (needs: [publish_aur]), doet alleen de POST en eindigt groen. publish_aur heeft allow_failure: true, dus een AUR-fout blokkeert de deploy niet.
Een release die de archive-route zelf wijzigt kan publish_aur één keer laten falen, omdat die job de oude binary gebruikt. De self-update daarna installeert de nieuwe route. Een retry van publish_aur publiceert dan alsnog.
BLUEGIT_UPDATE_TOKEN is een gemaskeerde, beschermde CI-variabele. Dezelfde waarde staat op de mini-PC in /etc/bluegit/env (EnvironmentFile, optioneel). Zonder die variabele antwoordt POST /api/v1/admin/self-update met 404. De vergelijking is constant-time, en een burst krijgt 429. De body mag leeg zijn of ref / sha bevatten. Het endpoint schrijft die ref naar /var/lib/bluegit/update-request en start alleen bluegit-update.service (systemctl start --no-block). De CI-job wacht daarna niet. Een poll in de job zou de herstart niet overleven, en de updater zou op die lopende job blijven wachten.
Bij bluegit serve zet BlueGit elke job die nog running is op failed. In het nieuwe proces heeft geen van die jobs nog een container. Het log zegt dat BlueGit herstartte terwijl de job liep. Daarna pakt retry met mode failed die job op, plus een vervolg dat daardoor was overgeslagen. Elke job met status running telt mee. publish_aur is dan al klaar en self_update eindigt bij de POST, vóór de bouw en pacman -U.
De polkit-regel packaging/bluegit-update.rules laat gebruiker bluegit uitsluitend start van die ene unit toe. Geen stop, geen restart, geen andere unit. De unit is een oneshot als root.
/usr/lib/bluegit/update (uit packaging/bluegit-update.sh) wacht tot GET /api/v1/admin/self-update "running":0 meldt, ook na de bouw en vóór pacman -U. Hij cloont niet van GitLab: BLUEGIT_UPDATE_REPO in /etc/bluegit/env wijst naar de lokale bare repo, bijvoorbeeld /srv/bluegit/tim/bluegit.git. pkgver is de UTC-committertijd van die commit (YYYYMMDDHHMMSS), dezelfde regel als het lokale AUR-script, zodat yay later geen downgrade of upgrade verzint voor dezelfde sha. makepkg draait als bluegit-build. Die gebruiker maakt de install-hook aan via systemd-sysusers (packaging/sysusers.conf). pacman -U --noconfirm installeert het pakket. post_upgrade in bluegit.install doet systemctl try-restart bluegit.service.
Mislukt de bouw of de installatie, dan blijft de oude versie staan. De uitvoer staat in het journal van bluegit-update.service en, vanaf deze versie, in /var/lib/bluegit/update.log. Elke run maakt dat bestand leeg en schrijft het opnieuw (mode 644). GET /api/v1/admin/self-update met dezelfde Bearer als de POST geeft running, status, sha, started_at, result, error en log (de laatste 200 regels). Het object update blijft. Het veld running blijft, want de updater wacht tot dat 0 is. Zonder sleutel is het antwoord 404, met een foute sleutel 401.
Een POST die 202 teruggeeft is nog geen installatie. De unit wacht tot BLUEGIT_UPDATE_TIMEOUT (standaard 1800 seconden) tot running 0 is, ook vóór pacman -U. Elke job met status running zit in die telling. openapi.json blijft 404 zolang de oude binary draait.
packaging/aur/PKGBUILD heeft geen check(). makepkg draait de testsuite niet en komt unshare dus niet tegen. De bouw is go build. pkgver komt uit git show op BLUEGIT_UPDATE_REPO. Die aanroep zet safe.directory: Git weigert ook als root een repo van een andere uid. Mislukt git, dan stopt het script en wordt de status failed. Het script dat nu geïnstalleerd is, is dat van het vorige pakket. Deze log en safe.directory gelden pas nadat een update deze versie echt geïnstalleerd heeft. Het script schrijft /var/lib/bluegit/update-status.json met tijd, sha en resultaat (running, ok, failed). Een installatiebeheerder ziet dat op de Info-pagina en op de setup-pagina.
De mini-PC heeft base-devel, go en pacman-contrib niet als package-dependency. Die moeten geïnstalleerd zijn, anders stopt het script vóór pacman -U.
Archief
Het archief van een commit is anoniem te downloaden zolang de repository publiek is. Een token is niet nodig. tar.gz en zip bestaan allebei. De map in het archief heet bluegit-<commit>, met de volledige sha.
https://git.timfalken.com/timfa/bluegit/-/archive/<commit>/bluegit-<commit>.tar.gz
https://git.timfalken.com/timfa/bluegit/-/archive/<commit>/bluegit-<commit>.zip
Twee downloads van dezelfde sha geven dezelfde bytes. git archive zet de gzip-mtime op 0, dus de klok zit niet in de checksum. sha256sums in de PKGBUILD hoort bij die url. Een andere git-versie op de server kan het archiefformaat wijzigen; dan klopt een al gepubliceerde checksum niet meer.
Een branch- of tagarchief (/-/branches/archive, /-/tags/archive) volgt de punt van die ref. Die url hoort niet in de PKGBUILD: de bytes veranderen zodra de ref opschuift, en dan breekt sha256sums.
De publish-job haalt de tarball zonder token op en zet de sha256 in de PKGBUILD. makepkg gebruikt dezelfde URL.