fp6-img/.forgejo/workflows/build.yml

119 lines
4.9 KiB
YAML
Raw Normal View History

name: image
# Builds the flashable Nura images for the Fairphone 6 (kernel from
# milos-linux combined-stable + imsd) — Plasma Mobile (fp6-img-plasma.tar.xz) and
# Phosh (fp6-img-phosh.tar.xz) — and publishes both as the rolling 'latest'
# release.
#
# Runs on the dedicated privileged runner label "pmos" (loop devices for
# pmbootstrap install, qemu-user binfmt on the host for the aarch64 chroots).
# Until that runner is registered, dispatched runs will sit queued.
on:
workflow_dispatch:
# push trigger is temporary, for pipeline bring-up; narrow to
# workflow_dispatch + a nightly schedule once the pipeline is green:
push:
branches: [main]
# schedule:
# - cron: '30 3 * * *'
jobs:
image:
runs-on: pmos
timeout-minutes: 420
steps:
# actions/checkout & friends are Node actions; bare alpine has no node.
2026-08-09 14:58:41 +02:00
# bash, curl, jq: required by the forgejo-release composite action —
# its setup_api falls back to apt-get when jq/curl are missing, which
# exits 127 on alpine.
- name: Provision job container
2026-08-09 14:58:41 +02:00
run: apk add -q nodejs git bash curl jq
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: true
- name: Build image (Plasma Mobile)
run: ./build.sh
# Second UI from the same package builds (the kernel and the aports
# above are already current in pmbootstrap's work dir, so this is the
# install + export only): fp6-img-phosh.tar.xz next to fp6-img-plasma.tar.xz
# in the same release.
- name: Build image (Phosh)
run: FP6IMG_UI=phosh FP6IMG_KEEP_DIST=1 ./build.sh
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: fp6-image-${{ github.sha }}
path: dist/*
if-no-files-found: error
drop the libqmi fork: Alpine's snapshot is past the !470 merge Alpine's community/libqmi is at upstream 1c972b8a (2026-10-05), 23 commits past the 30f3e998 this fork pinned "just past the !470 merge", with the qmi-glib 1.39.1 the GNSS patches in modemmanager need. No patch was left; the fork's one remaining addition, the FP6-tuned build (-march/-mtune, whose gain was never measured), goes with it. build.sh loses its tarball, checksum and build steps. The registry still serves the fork (1.39.1_git20260808-r100 and -r101), and that version outranks Alpine's 1.38.0_git* line, so with the aport alone installed phones keep the fork and a fresh image takes it back at its first 'apk upgrade': the fork's packages are deleted from the registry with this push. Fresh images then install Alpine's libqmi and keep it. Installed phones keep the fork until 'apk upgrade -a' downgrades them to Alpine's or Alpine's version passes 1.39.1; the new modemmanager works on either (verified on the FP6 with both). pmbootstrap keeps a local package repository in its work dir and consults it before every other repository. Whether that dir survives from one CI run to the next is not established (run 60 rebuilt libqmi, modemmanager and libcamera at the versions run 58 had built, which says it did not), but nothing guarantees it either way, so build.sh deletes any libqmi/qmi-utils apks found there before building, re-indexes the repository from the files present and fails the run if any are left; the publish step skips libqmi-*/qmi-utils-* as the backstop. pmbootstrap's 'zap --pkgs-local-mismatch' cannot do this: with systemd selected it looks at packages/systemd-edge, not at the packages/edge the builds land in.
2026-10-12 00:40:13 +02:00
# Ship every locally built apk (kernel, modemmanager, callaudioshim,
# audio files, ...) to the Forgejo Alpine registry, so
# installed systems get updates via 'apk upgrade' instead of losing
# the FP6 patches to the next upstream version bump. Requires the
# PACKAGE_TOKEN repo secret (catbot account, package:write scope);
# skips quietly until it exists. 409 = same version already published.
Install fingerprintd from the registry, so the image unlocks with a finger The daemon's own package CI publishes it to the registry the same way imsd's does, so the image takes it from there: the exact apk a user later gets via apk upgrade, sha256-pinned, re-signed for the chroot. Section 3b now fetches both sets, and every fetched file must have a pin -- the check used to be `grep . | sha256sum -c`, which an empty pin list would have sailed through with nothing checked. Three apks: the daemon, its systemd units, and the session agent, which does nothing until a user writes ~/.config/fingerprintd/fingers.conf. The daemon needs the kernel aport's CONFIG_QCOMTEE=m (pkgrel 101) and fp6-vendor-blobs 1-r2's mbn directive to reassemble the trustlet, both built in this run; 0.2.3 says >=1-r2 so a mismatched pair is refused rather than installed. The CI publish step skips fingerprintd-* like imsd-*: registry-sourced, not ours to republish. README: fingerprint in the list, and the two things a user will otherwise report as a dead sensor -- the lock screen listens for 60 seconds after it appears, and a held press is what the matcher was measured on -- plus the untested question of stock Android's own fingerprints after using this. Verified on the dev phone (fp6 repo journal/fingerprint/, 2026-09-05): the registry 0.2.2 package enrols through Plasma's Users page and unlocks the lock screen; 0.2.3 differs by the dependency and a post-upgrade restart. The image build itself, with the fprintd purge inside the chroot, runs first in CI.
2026-09-05 20:31:37 +02:00
# imsd and fingerprintd are skipped: build.sh 3b took them FROM the
# registry (re-signed for the chroot), so they are not ours to publish.
drop the libqmi fork: Alpine's snapshot is past the !470 merge Alpine's community/libqmi is at upstream 1c972b8a (2026-10-05), 23 commits past the 30f3e998 this fork pinned "just past the !470 merge", with the qmi-glib 1.39.1 the GNSS patches in modemmanager need. No patch was left; the fork's one remaining addition, the FP6-tuned build (-march/-mtune, whose gain was never measured), goes with it. build.sh loses its tarball, checksum and build steps. The registry still serves the fork (1.39.1_git20260808-r100 and -r101), and that version outranks Alpine's 1.38.0_git* line, so with the aport alone installed phones keep the fork and a fresh image takes it back at its first 'apk upgrade': the fork's packages are deleted from the registry with this push. Fresh images then install Alpine's libqmi and keep it. Installed phones keep the fork until 'apk upgrade -a' downgrades them to Alpine's or Alpine's version passes 1.39.1; the new modemmanager works on either (verified on the FP6 with both). pmbootstrap keeps a local package repository in its work dir and consults it before every other repository. Whether that dir survives from one CI run to the next is not established (run 60 rebuilt libqmi, modemmanager and libcamera at the versions run 58 had built, which says it did not), but nothing guarantees it either way, so build.sh deletes any libqmi/qmi-utils apks found there before building, re-indexes the repository from the files present and fails the run if any are left; the publish step skips libqmi-*/qmi-utils-* as the backstop. pmbootstrap's 'zap --pkgs-local-mismatch' cannot do this: with systemd selected it looks at packages/systemd-edge, not at the packages/edge the builds land in.
2026-10-12 00:40:13 +02:00
# libqmi is skipped too: its fork was retired and deleted from the
# registry (2026-10-12); should a leftover apk ever sit in the runner's
# package dir, it must not bring the fork back.
- name: Publish packages to the apk registry
env:
PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }}
run: |
if [ -z "$PACKAGE_TOKEN" ]; then
echo "no PACKAGE_TOKEN secret configured; skipping package publish"
exit 0
fi
apk add -q curl
found=0
for f in /home/build/.local/var/pmbootstrap/packages/*/aarch64/*.apk; do
[ -e "$f" ] || continue
case "$(basename "$f")" in
Install fingerprintd from the registry, so the image unlocks with a finger The daemon's own package CI publishes it to the registry the same way imsd's does, so the image takes it from there: the exact apk a user later gets via apk upgrade, sha256-pinned, re-signed for the chroot. Section 3b now fetches both sets, and every fetched file must have a pin -- the check used to be `grep . | sha256sum -c`, which an empty pin list would have sailed through with nothing checked. Three apks: the daemon, its systemd units, and the session agent, which does nothing until a user writes ~/.config/fingerprintd/fingers.conf. The daemon needs the kernel aport's CONFIG_QCOMTEE=m (pkgrel 101) and fp6-vendor-blobs 1-r2's mbn directive to reassemble the trustlet, both built in this run; 0.2.3 says >=1-r2 so a mismatched pair is refused rather than installed. The CI publish step skips fingerprintd-* like imsd-*: registry-sourced, not ours to republish. README: fingerprint in the list, and the two things a user will otherwise report as a dead sensor -- the lock screen listens for 60 seconds after it appears, and a held press is what the matcher was measured on -- plus the untested question of stock Android's own fingerprints after using this. Verified on the dev phone (fp6 repo journal/fingerprint/, 2026-09-05): the registry 0.2.2 package enrols through Plasma's Users page and unlocks the lock screen; 0.2.3 differs by the dependency and a post-upgrade restart. The image build itself, with the fprintd purge inside the chroot, runs first in CI.
2026-09-05 20:31:37 +02:00
imsd-*|fingerprintd-*) echo "registry-sourced, not republished: $(basename "$f")"; continue ;;
drop the libqmi fork: Alpine's snapshot is past the !470 merge Alpine's community/libqmi is at upstream 1c972b8a (2026-10-05), 23 commits past the 30f3e998 this fork pinned "just past the !470 merge", with the qmi-glib 1.39.1 the GNSS patches in modemmanager need. No patch was left; the fork's one remaining addition, the FP6-tuned build (-march/-mtune, whose gain was never measured), goes with it. build.sh loses its tarball, checksum and build steps. The registry still serves the fork (1.39.1_git20260808-r100 and -r101), and that version outranks Alpine's 1.38.0_git* line, so with the aport alone installed phones keep the fork and a fresh image takes it back at its first 'apk upgrade': the fork's packages are deleted from the registry with this push. Fresh images then install Alpine's libqmi and keep it. Installed phones keep the fork until 'apk upgrade -a' downgrades them to Alpine's or Alpine's version passes 1.39.1; the new modemmanager works on either (verified on the FP6 with both). pmbootstrap keeps a local package repository in its work dir and consults it before every other repository. Whether that dir survives from one CI run to the next is not established (run 60 rebuilt libqmi, modemmanager and libcamera at the versions run 58 had built, which says it did not), but nothing guarantees it either way, so build.sh deletes any libqmi/qmi-utils apks found there before building, re-indexes the repository from the files present and fails the run if any are left; the publish step skips libqmi-*/qmi-utils-* as the backstop. pmbootstrap's 'zap --pkgs-local-mismatch' cannot do this: with systemd selected it looks at packages/systemd-edge, not at the packages/edge the builds land in.
2026-10-12 00:40:13 +02:00
libqmi-*|qmi-utils-*) echo "retired fork, not republished: $(basename "$f")"; continue ;;
esac
found=1
code=$(curl -s -o /dev/null -w '%{http_code}' \
--user "catbot:$PACKAGE_TOKEN" --upload-file "$f" \
"https://forgejo.catcrafts.net/api/packages/Catcrafts/alpine/edge/fp6")
case "$code" in
201) echo "published: $(basename "$f")" ;;
409) echo "already published: $(basename "$f")" ;;
*) echo "FAILED ($code): $(basename "$f")"; exit 1 ;;
esac
done
[ "$found" = 1 ] || { echo "no packages found to publish"; exit 1; }
- name: Update rolling 'latest' tag
run: |
git config --global --add safe.directory "$PWD"
git config user.email "ci@catcrafts.net"
git config user.name "fp6-img CI"
git tag -f latest
git push origin latest --force
- name: Publish rolling 'latest' release
uses: https://code.forgejo.org/actions/forgejo-release@v2
with:
direction: upload
url: ${{ github.server_url }}
repo: ${{ github.repository }}
tag: latest
title: Latest FP6 Nura image
prerelease: true
override: true
release-dir: dist
token: ${{ secrets.GITHUB_TOKEN }}
2026-08-10 16:22:20 +02:00
# Empty, NOT 'false': the action guards its release-notes-assistant
# cache step with `if: ${{ inputs.release-notes-assistant }}`, where
# the default string 'false' is truthy. That step then can't reach the
# runner's cache server (it advertises the host's public IP) and burns
# ~4m40s per run on a connect timeout before reporting a miss.
release-notes-assistant: ''