fingerprintd/packaging/build-package.sh

131 lines
6.4 KiB
Shell
Raw Normal View History

Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
#!/bin/sh -eu
# SPDX-License-Identifier: GPL-3.0-only
# SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
# CI package build: cross-compile fingerprintd for aarch64 with crafter-build
# (the README's "Cross-compiling" flow), run the test suite natively, and
# package the result via packaging/APKBUILD. Expects an x86_64 Alpine
# environment with root — the workflow runs it in an alpine:edge job
packaging, ci: build the apk with the Crafter.Build Flatpak Crafter.Build's releases carry a Flatpak and nothing else since 2026-10-02 (imsd a625248): the rolling `latest` release's crafter-build-linux-x86_64-musl-v2.tar.gz that build-package.sh fetched is gone, so the push of 0.2.6 failed at `fetch crafter-build` (run 10, 2026-10-14, three 404s) and published nothing; the registry still serves 0.2.5. The move imsd made on 2026-10-04: install the Flatpak (net.catcrafts.CrafterBuild//stable from flatpak.catcrafts.net) in the job container and run it as crafter-build. bubblewrap inside the container needs a privileged runner, so the job runs on the `flatpak` label. The host keeps clang and llvm-ar for libqcomtee, which make-libqcomtee.sh compiles against the sysroot; the daemon's compiler, lld and libc++ are the Flatpak's, so the host packages that served the native test-suite run go. The sysroot gains llvm-runtimes, the package with the std module source of its own libc++ (libc++-dev ships none), added with --upgrade so a sysroot from before this change comes out with a matching libc++ and source. The README's Build section carries the install lines. Tested: build-package.sh run end to end on this commit in a privileged alpine:edge container (podman) on the workstation: crafter-build 2.1.0 (clang 23.1.2) from `stable`, the sysroot at libc++ and llvm-runtimes 23.1.3, daemon and agent cross-built, 8 suites passed natively, the three apks built, the daemon an aarch64 PIE against the sysroot's musl and libc++ (65 s). The rehearsed copy differs from this commit by the wrapping of one comment line.
2026-10-14 02:32:30 +02:00
# container on the privileged `flatpak` runner: crafter-build is the
# Crafter.Build Flatpak, and bubblewrap inside the container needs the
# privilege. Root only installs packages and hands off to a scratch user:
# the sysroot is built with apk.static --usermode (which refuses root) and
# abuild wants a user too.
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
#
# Built packages land in /home/build/.local/share/abuild/*/aarch64/fingerprintd*.apk;
# the workflow's publish step uploads them to the Forgejo Alpine registry.
set -eu
packaging, ci: build the apk with the Crafter.Build Flatpak Crafter.Build's releases carry a Flatpak and nothing else since 2026-10-02 (imsd a625248): the rolling `latest` release's crafter-build-linux-x86_64-musl-v2.tar.gz that build-package.sh fetched is gone, so the push of 0.2.6 failed at `fetch crafter-build` (run 10, 2026-10-14, three 404s) and published nothing; the registry still serves 0.2.5. The move imsd made on 2026-10-04: install the Flatpak (net.catcrafts.CrafterBuild//stable from flatpak.catcrafts.net) in the job container and run it as crafter-build. bubblewrap inside the container needs a privileged runner, so the job runs on the `flatpak` label. The host keeps clang and llvm-ar for libqcomtee, which make-libqcomtee.sh compiles against the sysroot; the daemon's compiler, lld and libc++ are the Flatpak's, so the host packages that served the native test-suite run go. The sysroot gains llvm-runtimes, the package with the std module source of its own libc++ (libc++-dev ships none), added with --upgrade so a sysroot from before this change comes out with a matching libc++ and source. The README's Build section carries the install lines. Tested: build-package.sh run end to end on this commit in a privileged alpine:edge container (podman) on the workstation: crafter-build 2.1.0 (clang 23.1.2) from `stable`, the sysroot at libc++ and llvm-runtimes 23.1.3, daemon and agent cross-built, 8 suites passed natively, the three apks built, the daemon an aarch64 PIE against the sysroot's musl and libc++ (65 s). The rehearsed copy differs from this commit by the wrapping of one comment line.
2026-10-14 02:32:30 +02:00
# crafter-build is the Crafter.Build Flatpak: it carries its own clang, lld
# and libc++, and its SDK has glib, so nothing the daemon's build compiles
# with is installed here. `stable` is the branch Crafter.Build publishes from
# its release tags (`beta` follows every push to its master), so the
# toolchain of a release moves only with a release of the toolchain. The
# branch is overridable for a rehearsal against another one.
CRAFTER_REMOTE=${CRAFTER_REMOTE:-https://flatpak.catcrafts.net/catcrafts.flatpakrepo}
CRAFTER_REF=${CRAFTER_REF:-net.catcrafts.CrafterBuild//stable}
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
SRC=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)
packaging, ci: build the apk with the Crafter.Build Flatpak Crafter.Build's releases carry a Flatpak and nothing else since 2026-10-02 (imsd a625248): the rolling `latest` release's crafter-build-linux-x86_64-musl-v2.tar.gz that build-package.sh fetched is gone, so the push of 0.2.6 failed at `fetch crafter-build` (run 10, 2026-10-14, three 404s) and published nothing; the registry still serves 0.2.5. The move imsd made on 2026-10-04: install the Flatpak (net.catcrafts.CrafterBuild//stable from flatpak.catcrafts.net) in the job container and run it as crafter-build. bubblewrap inside the container needs a privileged runner, so the job runs on the `flatpak` label. The host keeps clang and llvm-ar for libqcomtee, which make-libqcomtee.sh compiles against the sysroot; the daemon's compiler, lld and libc++ are the Flatpak's, so the host packages that served the native test-suite run go. The sysroot gains llvm-runtimes, the package with the std module source of its own libc++ (libc++-dev ships none), added with --upgrade so a sysroot from before this change comes out with a matching libc++ and source. The README's Build section carries the install lines. Tested: build-package.sh run end to end on this commit in a privileged alpine:edge container (podman) on the workstation: crafter-build 2.1.0 (clang 23.1.2) from `stable`, the sysroot at libc++ and llvm-runtimes 23.1.3, daemon and agent cross-built, 8 suites passed natively, the three apks built, the daemon an aarch64 PIE against the sysroot's musl and libc++ (65 s). The rehearsed copy differs from this commit by the wrapping of one comment line.
2026-10-14 02:32:30 +02:00
retry() { # retry <description> <cmd...>
_desc=$1; shift
for _i in 1 2 3; do
"$@" && return 0
echo "$_desc failed (attempt $_i/3), retrying in 15s..." >&2
sleep 15
done
echo "$_desc failed after 3 attempts" >&2
return 1
}
# clang and llvm-ar here are for libqcomtee: make-libqcomtee.sh compiles it
# with the host clang against the sysroot (C, objects and an archive, no
# link). llvm also has llvm-strip, which abuild in cross mode strips with.
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
if [ "$(id -u)" = 0 ]; then
packaging, ci: build the apk with the Crafter.Build Flatpak Crafter.Build's releases carry a Flatpak and nothing else since 2026-10-02 (imsd a625248): the rolling `latest` release's crafter-build-linux-x86_64-musl-v2.tar.gz that build-package.sh fetched is gone, so the push of 0.2.6 failed at `fetch crafter-build` (run 10, 2026-10-14, three 404s) and published nothing; the registry still serves 0.2.5. The move imsd made on 2026-10-04: install the Flatpak (net.catcrafts.CrafterBuild//stable from flatpak.catcrafts.net) in the job container and run it as crafter-build. bubblewrap inside the container needs a privileged runner, so the job runs on the `flatpak` label. The host keeps clang and llvm-ar for libqcomtee, which make-libqcomtee.sh compiles against the sysroot; the daemon's compiler, lld and libc++ are the Flatpak's, so the host packages that served the native test-suite run go. The sysroot gains llvm-runtimes, the package with the std module source of its own libc++ (libc++-dev ships none), added with --upgrade so a sysroot from before this change comes out with a matching libc++ and source. The README's Build section carries the install lines. Tested: build-package.sh run end to end on this commit in a privileged alpine:edge container (podman) on the workstation: crafter-build 2.1.0 (clang 23.1.2) from `stable`, the sysroot at libc++ and llvm-runtimes 23.1.3, daemon and agent cross-built, 8 suites passed natively, the three apks built, the daemon an aarch64 PIE against the sysroot's musl and libc++ (65 s). The rehearsed copy differs from this commit by the wrapping of one comment line.
2026-10-14 02:32:30 +02:00
apk add -q git curl tar flatpak clang llvm abuild sudo
# the Flatpak as a system installation the build user runs; its SDK
# (org.freedesktop.Sdk) comes from Flathub
flatpak remote-add --if-not-exists catcrafts "$CRAFTER_REMOTE"
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
retry "install crafter-build" flatpak install -y --noninteractive catcrafts "$CRAFTER_REF"
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
id build >/dev/null 2>&1 || adduser -D build
addgroup build abuild 2>/dev/null || true
echo 'build ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/build
# abuild in cross mode strips with $CHOST-strip; llvm-strip handles any
# ELF arch, so give it that name
ln -sf "$(command -v llvm-strip)" /usr/local/bin/aarch64-alpine-linux-musl-strip
# the CI checkout arrives root-owned; crafter-build writes bin/ into it
chown -R build "$SRC"
# -l: a login shell, so HOME really is /home/build (abuild keys + output);
# it scrubs the environment, so carry the one knob that matters across
packaging, ci: build the apk with the Crafter.Build Flatpak Crafter.Build's releases carry a Flatpak and nothing else since 2026-10-02 (imsd a625248): the rolling `latest` release's crafter-build-linux-x86_64-musl-v2.tar.gz that build-package.sh fetched is gone, so the push of 0.2.6 failed at `fetch crafter-build` (run 10, 2026-10-14, three 404s) and published nothing; the registry still serves 0.2.5. The move imsd made on 2026-10-04: install the Flatpak (net.catcrafts.CrafterBuild//stable from flatpak.catcrafts.net) in the job container and run it as crafter-build. bubblewrap inside the container needs a privileged runner, so the job runs on the `flatpak` label. The host keeps clang and llvm-ar for libqcomtee, which make-libqcomtee.sh compiles against the sysroot; the daemon's compiler, lld and libc++ are the Flatpak's, so the host packages that served the native test-suite run go. The sysroot gains llvm-runtimes, the package with the std module source of its own libc++ (libc++-dev ships none), added with --upgrade so a sysroot from before this change comes out with a matching libc++ and source. The README's Build section carries the install lines. Tested: build-package.sh run end to end on this commit in a privileged alpine:edge container (podman) on the workstation: crafter-build 2.1.0 (clang 23.1.2) from `stable`, the sysroot at libc++ and llvm-runtimes 23.1.3, daemon and agent cross-built, 8 suites passed natively, the three apks built, the daemon an aarch64 PIE against the sysroot's musl and libc++ (65 s). The rehearsed copy differs from this commit by the wrapping of one comment line.
2026-10-14 02:32:30 +02:00
exec su -l build -c "CRAFTER_REF='$CRAFTER_REF' sh -eu '$SRC/packaging/build-package.sh'"
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
fi
# interfaces/Fingerprintd.cppm is the version's single source of truth (same
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
# derivation as make-bin-tarball.sh)
VER=$(sed -n 's/.*Version = "\(.*\)".*/\1/p' "$SRC/interfaces/Fingerprintd.cppm")
[ -n "$VER" ] || { echo "cannot read Version from interfaces/Fingerprintd.cppm" >&2; exit 1; }
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
echo ">> packaging fingerprintd $VER"
packaging, ci: build the apk with the Crafter.Build Flatpak Crafter.Build's releases carry a Flatpak and nothing else since 2026-10-02 (imsd a625248): the rolling `latest` release's crafter-build-linux-x86_64-musl-v2.tar.gz that build-package.sh fetched is gone, so the push of 0.2.6 failed at `fetch crafter-build` (run 10, 2026-10-14, three 404s) and published nothing; the registry still serves 0.2.5. The move imsd made on 2026-10-04: install the Flatpak (net.catcrafts.CrafterBuild//stable from flatpak.catcrafts.net) in the job container and run it as crafter-build. bubblewrap inside the container needs a privileged runner, so the job runs on the `flatpak` label. The host keeps clang and llvm-ar for libqcomtee, which make-libqcomtee.sh compiles against the sysroot; the daemon's compiler, lld and libc++ are the Flatpak's, so the host packages that served the native test-suite run go. The sysroot gains llvm-runtimes, the package with the std module source of its own libc++ (libc++-dev ships none), added with --upgrade so a sysroot from before this change comes out with a matching libc++ and source. The README's Build section carries the install lines. Tested: build-package.sh run end to end on this commit in a privileged alpine:edge container (podman) on the workstation: crafter-build 2.1.0 (clang 23.1.2) from `stable`, the sysroot at libc++ and llvm-runtimes 23.1.3, daemon and agent cross-built, 8 suites passed natively, the three apks built, the daemon an aarch64 PIE against the sysroot's musl and libc++ (65 s). The rehearsed copy differs from this commit by the wrapping of one comment line.
2026-10-14 02:32:30 +02:00
# --- crafter-build: the Flatpak, under the name the rest of this file uses.
# The build log names the build it ran with.
mkdir -p "$HOME/bin"
printf '#!/bin/sh\nexec flatpak run %s "$@"\n' "$CRAFTER_REF" > "$HOME/bin/crafter-build"
chmod +x "$HOME/bin/crafter-build"
PATH="$HOME/bin:$PATH"
flatpak info "$CRAFTER_REF" | sed -n 's/^ *\(Version\|Commit\|Date\): */crafter-build \1: /p'
crafter-build --version
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
# --- aarch64 Alpine sysroot (unprivileged: apk.static --usermode)
SYSROOT="$HOME/.cache/fingerprintd/sysroot-aarch64-alpine"
retry "make sysroot" "$SRC/packaging/make-sysroot.sh" "$SYSROOT"
# --- libqcomtee: Qualcomm's BSD-3 QTEE client (quic-teec, pinned commit),
# which is not in Alpine and is not vendored here. crafter-build looks for it
# under ~/.cache/fingerprintd/libqcomtee-<target>, which is this script's
# default output dir. Needs git, installed above.
retry "make libqcomtee" "$SRC/packaging/make-libqcomtee.sh" \
--target=aarch64-alpine-linux-musl --sysroot="$SYSROOT" --march=armv8.6-a+fp16fml+aes+sha3+sm4
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
# --- cross-compile the daemon; run the suites natively. The core is portable
# by construction (no GLib, no libqcomtee, no system headers), which is what
# lets the wire formats and state machines be tested on the build host at all.
cd "$SRC"
# The phone is one SoC, 4x Cortex-A520 + 4x Cortex-A720, so build for it (the
# same -march goes to libqcomtee above). armv8.6-a is the highest level whose
# mandatory set it exposes (8.7 would assume WFxT, 9.x SVE2 - neither is in
# its hwcaps); +fp16fml+aes+sha3+sm4 are the optional extensions it has. Same
# string as the fp6-img aports.
XTARGET="--target=aarch64-alpine-linux-musl --sysroot=$SYSROOT --march=armv8.6-a+fp16fml+aes+sha3+sm4 --mtune=cortex-a720"
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
crafter-build -- $XTARGET
crafter-build -- --product=agent $XTARGET
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
crafter-build test
# --- bundle + package
./packaging/make-bin-tarball.sh "$VER"
PKG="$HOME/pkg"
rm -rf "$PKG"
mkdir -p "$PKG"
cp "$SRC/packaging/APKBUILD" "$PKG/APKBUILD"
# install= scripts are read from the aport dir, not from source=
cp "$SRC/packaging/fingerprintd.post-install" "$SRC/packaging/fingerprintd.post-upgrade" "$PKG/"
Package the daemon, so a fingerprint survives a reflash An aport, the units, and everything a phone needs to come up with a working sensor without a single command being run by hand. Verified on the dev phone across two reboots: modules-load.d loads qcomtee, tmpfiles builds the SFS root, the mount unit brings up persist, and the daemon is ready 51 seconds into the boot, owning net.reactivated.Fprint with the enrolled finger visible. The packaging shape is the one imsd uses for 81voltd. A versioned provides="fprintd=..." satisfies plasma-workspace -- its Users KCM is the enrolment UI and speaks exactly this bus name -- and excludes the real fprintd, which is not tidiness: fprintd is D-Bus-activatable, so a client call would otherwise start it and fight us for the name. The cost is the fprintd-* CLIs, which go with the package. fprintd-pam is an install_if subpackage pinned to the exact fprintd version, so the provides breaks its condition and apk purges it -- taking pam_fprintd, which is the entire point of the daemon, with it. Depending on it explicitly is what keeps it, and it has no dependency on fprintd itself. Two things the packaging exposed in the daemon: The transcript is for experiments, not for a shipped daemon. A file per start in an unrotated directory, recording the time of every unlock, to say what the journal already has. It is now opt-in behind --log-dir, which is what deploy-dev.sh passes since fplearn.sh reads it. Taking it off the daemon path also took away the setvbuf it was doing as a side effect of dup2'ing fd 1, and under systemd stdout is a pipe, which means full buffering: the daemon started, worked, answered D-Bus calls, and printed nothing. A working daemon that looks hung. stdout is now line-buffered from the first line of main. The config ships as generated by fp6fpcfg.py --daemon --verbose, sha256 b205c756914a66f1, because that is the file every accuracy number was measured on. The quieter variant is untested and switching is a measurement. The trustlet is not here and never will be: focal64.mbn is a proprietary OEM-signed blob, and the unit's ConditionPathExists is what keeps the package inert without it -- as it does on a kernel with no CONFIG_QCOMTEE.
2026-09-05 02:52:01 +02:00
mv "fingerprintd-$VER.tar.gz" "$PKG/"
sed -i "s/^pkgver=.*/pkgver=$VER/" "$PKG/APKBUILD"
# a throwaway signing key: phones trust the registry-signed APKINDEX, not
# per-package keys (same situation as fp6-img's pmbootstrap-built packages).
# abuild >= 3.18 keeps keys under ~/.config/abuild and output under
# ~/.local/share/abuild (REPODEST default).
abuild-keygen -a -n >/dev/null 2>&1
sudo cp "$HOME"/.config/abuild/*.rsa.pub /etc/apk/keys/
# CHOST puts abuild in cross mode so arch="aarch64" packages on this x86_64
# host. -d skips dependency handling entirely: nothing compiles under abuild
# (with -r, cross mode would try to install a nonexistent build-base-aarch64
# plus the runtime depends); !tracedeps in the APKBUILD keeps abuild from
# resolving the aarch64 ELF NEEDED entries against this x86_64 host.
cd "$PKG"
abuild checksum
CHOST=aarch64 abuild -d
echo "=== built packages ==="
ls -la "$HOME"/.local/share/abuild/*/aarch64/fingerprintd*.apk