fp6-img/.forgejo/workflows/build.yml
Jorijn van der Graaf e7a1825b50
Some checks failed
image / image (push) Failing after 48m0s
imsd: install the published apk instead of building it
The imsd repo's package CI is now the only producer of the imsd apk. The
image installs the exact registry package users get via 'apk upgrade'
(pinned version + sha256 of the registry files), so the two can no longer
diverge and the payload-parity rule between two packagings is gone.

pmbootstrap has no knob for a third-party repository, and after the main
'apk add' it re-adds every package in its local packages dir by file path,
which makes apk verify the package's own signature. Registry packages are
signed with per-run keys nobody keeps (phones trust the registry-signed
index), so apk-resign.py replaces the signature stream with one from this
run's abuild key; control and data streams stay byte-identical and the
identity checksum equals the registry's. Verified on the host with apk
3.0.8: originals UNTRUSTED, re-signed OK, checksums equal.

The publish step skips imsd-*: those files came from the registry.
2026-09-02 16:11:50 +02:00

107 lines
4.2 KiB
YAML

name: image
# Builds a flashable postmarketOS image for the Fairphone 6 (kernel from
# milos-linux combined-stable + imsd) and publishes it 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.
# 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
run: apk add -q nodejs git bash curl jq
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: true
- name: Build image
run: ./build.sh
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: fp6-image-${{ github.sha }}
path: dist/*
if-no-files-found: error
# Ship every locally built apk (kernel, modemmanager, libqmi,
# 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.
# imsd is skipped: build.sh 3b took it FROM the registry (re-signed
# for the chroot), so it is not ours to publish.
- 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
imsd-*) echo "registry-sourced, 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 postmarketOS image
prerelease: true
override: true
release-dir: dist
token: ${{ secrets.GITHUB_TOKEN }}
# 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: ''