Compare commits
5 changed files with 94 additions and 100 deletions
|
|
@ -7,10 +7,9 @@ name: package
|
|||
#
|
||||
# Build: crafter-build cross-compiles against an Alpine aarch64 sysroot
|
||||
# (packaging/build-package.sh — the README's "Cross-compiling" flow), the test
|
||||
# suite runs natively, and packaging/APKBUILD wraps the result. crafter-build
|
||||
# is the Crafter.Build Flatpak, and bubblewrap inside the job container needs
|
||||
# a privileged runner: the job runs on the `flatpak` label (the Catcrafts
|
||||
# organisation's privileged runner), in an alpine:edge container.
|
||||
# suite runs natively, and packaging/APKBUILD wraps the result. This needs no
|
||||
# privileged runner: it runs in an alpine:edge container on the ordinary
|
||||
# arch-latest runner.
|
||||
#
|
||||
# Release gating is the version: pkgver comes from interfaces/Fingerprintd.cppm,
|
||||
# the registry answers 409 for an already-published version, and the publish
|
||||
|
|
@ -28,7 +27,7 @@ on:
|
|||
|
||||
jobs:
|
||||
package:
|
||||
runs-on: flatpak
|
||||
runs-on: arch-latest
|
||||
container:
|
||||
image: alpine:edge
|
||||
timeout-minutes: 90
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
# Read by Forgejo for the repository's Donate button.
|
||||
custom: 'https://catcrafts.net/shop/donation'
|
||||
107
README.md
107
README.md
|
|
@ -8,6 +8,24 @@ recovered by reverse-engineering, so all of it is pinned by tests that run on a
|
|||
dev box with no phone, no TEE and no sensor. The daemon shell holds everything
|
||||
that touches hardware.
|
||||
|
||||
## Build
|
||||
|
||||
```sh
|
||||
crafter-build # bin/fingerprintd-<target>-<march>/fingerprintd
|
||||
crafter-build test # the unit suites
|
||||
```
|
||||
|
||||
Cross-compiling for the phone:
|
||||
|
||||
```sh
|
||||
packaging/make-sysroot.sh
|
||||
crafter-build -- --target=aarch64-alpine-linux-musl --sysroot=~/.cache/fingerprintd/sysroot-aarch64-alpine --march=armv8.6-a+fp16fml+aes+sha3+sm4 --mtune=cortex-a720
|
||||
crafter-build test --target=aarch64-alpine-linux-musl --sysroot=~/.cache/fingerprintd/sysroot-aarch64-alpine --march=armv8.6-a+fp16fml+aes+sha3+sm4 --mtune=cortex-a720
|
||||
```
|
||||
|
||||
Verified on the device: all five suites pass cross-built and run on the phone
|
||||
itself, not only under emulation.
|
||||
|
||||
```
|
||||
fprintd-enroll -f right-index-finger user ten stages, enroll-completed
|
||||
fprintd-list user - #0: right-index-finger
|
||||
|
|
@ -38,62 +56,55 @@ Two routes, both on by default:
|
|||
announced as `FingerMatched` for the session agent. `--standby-unlock=off`
|
||||
disables it.
|
||||
|
||||
## Per-finger macros
|
||||
|
||||
The trustlet reports *which* finger matched, so a finger can mean more than
|
||||
"it was you". Two files, in two trust domains:
|
||||
|
||||
- **`~/.config/fingerprintd/fingers.conf`** runs a command as you, in your
|
||||
session. This is how a finger opens an application.
|
||||
- **`/etc/fingerprintd/actions.conf`** runs a command as root, and can mark a
|
||||
finger as one that never unlocks.
|
||||
|
||||
### In your session: `fingers.conf`
|
||||
|
||||
```
|
||||
# ~/.config/fingerprintd/fingers.conf
|
||||
right-ring-finger kde-open camera
|
||||
left-index-finger plasma-settings
|
||||
left-thumb sh -c 'notify-send "hello from a finger"'
|
||||
```
|
||||
|
||||
- using these requires the fingerprintd-agent service to be running.
|
||||
|
||||
### As root: `actions.conf`
|
||||
|
||||
```
|
||||
# /etc/fingerprintd/actions.conf
|
||||
# <finger> [no-unlock] [absolute command...]
|
||||
right-ring-finger /usr/local/bin/toggle-something
|
||||
left-little-finger no-unlock /etc/fingerprintd/panic.sh
|
||||
left-thumb no-unlock
|
||||
```
|
||||
|
||||
- `no-unlock`: the finger matches and the client is told it did not. PAM
|
||||
sees `verify-no-match`, the standby unlock stays locked. The command, if
|
||||
there is one, runs regardless.
|
||||
- the command: an absolute path, run by root through `/bin/sh -c` with a
|
||||
fixed `PATH` and `FINGERPRINTD_FINGER` set to the finger's name, detached
|
||||
from the daemon with its stdio on `/dev/null`, so it may block or reboot
|
||||
the phone without stalling the sensor.
|
||||
- a line needs at least one of the two, and a finger gets at most one line.
|
||||
- editing this file requires a restart of the fingerprintd service before changes take effect.
|
||||
|
||||
|
||||
## Runtime dependencies
|
||||
|
||||
The `focal64` trustlet is proprietary and is not in this repo. It is
|
||||
extracted from the device's own stock Android partition on first boot by the
|
||||
`fp6-vendor-blobs` mechanism, the same way other firmware in fp6-img is.
|
||||
|
||||
## Releases
|
||||
|
||||
Every push to `main` is built and tested by CI, which then publishes the
|
||||
apks to the Forgejo Alpine registry that installed phones already point at.
|
||||
CI treats the registry's "already published" answer as nothing to do, so a
|
||||
push publishes only a package version new to the registry. The package
|
||||
version is `pkgver-rpkgrel`: `pkgver` is the `Version` constant in
|
||||
`interfaces/Fingerprintd.cppm`, `pkgrel` is the APKBUILD's and stays at 0.
|
||||
An installed phone picks a published version up with plain `apk upgrade`.
|
||||
|
||||
From 0.2.6 on, a release is a range of commits ending in a bump commit
|
||||
titled `fingerprintd X.Y.Z` that changes only the version: the constant and
|
||||
the APKBUILD's `pkgver`. Each release is tagged `vX.Y.Z` on its bump commit
|
||||
(signed, annotated) with the release notes as the tag message, and
|
||||
published as a Forgejo release of the same name and text. No version
|
||||
before 0.2.6 has a tag or release notes. The notes are written for the
|
||||
people whose phones will upgrade:
|
||||
|
||||
```
|
||||
fingerprintd X.Y.Z
|
||||
|
||||
## New
|
||||
|
||||
- **What a user can now do.** One bullet per change, the most important
|
||||
first, with anything the user has to do inside the bullet.
|
||||
|
||||
## Fixes
|
||||
|
||||
- **What went wrong, in the user's terms.** What they saw, what changes,
|
||||
what to do.
|
||||
```
|
||||
|
||||
A section with nothing in it is left out, and so is behaviour the release
|
||||
does not change. Versioning, from 0.2.6 on, is `MAJOR.MINOR.PATCH`: the
|
||||
patch number counts releases, fixes and features alike; the minor number
|
||||
moves when a release changes what a user can rely on the daemon for; the
|
||||
major number moves when a release changes what an installed phone does
|
||||
without being asked.
|
||||
|
||||
## License
|
||||
|
||||
GPL-3.0-only - see [LICENSE](LICENSE).
|
||||
|
||||
## Funding
|
||||
|
||||
https://catcrafts.net/shop/donation - see [FUNDING](FUNDING.yml)
|
||||
GPL-3.0-only, see LICENSE.
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright (C) 2026 Catcrafts® [catcrafts.net](https://catcrafts.net/)
|
||||
Copyright (C) 2026 Catcrafts® catcrafts.net
|
||||
|
|
@ -5,28 +5,44 @@
|
|||
# (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
|
||||
# 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.
|
||||
# container on an ordinary runner. 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.
|
||||
#
|
||||
# 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
|
||||
|
||||
# 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}
|
||||
# The musl build of crafter-build (Crafter.Build CI's release-musl job): this
|
||||
# container is Alpine, and the glibc launcher cannot run on musl. v2 = SSE4.2
|
||||
# baseline: the CI box is an Intel N5105 (no AVX). Overridable for local
|
||||
# rehearsals (file:// works).
|
||||
CRAFTER_URL=${CRAFTER_URL:-https://forgejo.catcrafts.net/Catcrafts/Crafter.Build/releases/download/latest/crafter-build-linux-x86_64-musl-v2.tar.gz}
|
||||
|
||||
SRC=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)
|
||||
|
||||
# clang cross-targets aarch64 natively and the target's libc++/glib come from
|
||||
# the sysroot; llvm-runtimes/libc++-dev/glib-dev here serve the NATIVE
|
||||
# test-suite run. build-base = Alpine's standard build environment (the one
|
||||
# abuild implies): binutils' ld/ar for clang's default link driver, gcc's
|
||||
# libgcc_s/crt objects the musl clang driver links against.
|
||||
if [ "$(id -u)" = 0 ]; then
|
||||
apk add -q git curl tar clang lld llvm llvm-runtimes libc++-dev llvm-libunwind-dev glib-dev \
|
||||
build-base abuild sudo
|
||||
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
|
||||
exec su -l build -c "CRAFTER_URL='${CRAFTER_URL:-}' sh -eu '$SRC/packaging/build-package.sh'"
|
||||
fi
|
||||
|
||||
retry() { # retry <description> <cmd...>
|
||||
_desc=$1; shift
|
||||
for _i in 1 2 3; do
|
||||
|
|
@ -38,43 +54,18 @@ retry() { # retry <description> <cmd...>
|
|||
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.
|
||||
if [ "$(id -u)" = 0 ]; then
|
||||
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"
|
||||
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
|
||||
exec su -l build -c "CRAFTER_REF='$CRAFTER_REF' sh -eu '$SRC/packaging/build-package.sh'"
|
||||
fi
|
||||
|
||||
# interfaces/Fingerprintd.cppm is the version's single source of truth (same
|
||||
# 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; }
|
||||
echo ">> packaging fingerprintd $VER"
|
||||
|
||||
# --- 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
|
||||
# --- crafter-build: static launcher from the rolling release
|
||||
mkdir -p "$HOME/crafter-build"
|
||||
retry "fetch crafter-build" \
|
||||
sh -c "curl -fsSL '$CRAFTER_URL' | tar -xz -C '$HOME/crafter-build'"
|
||||
PATH="$HOME/crafter-build/bin:$PATH"
|
||||
export CRAFTER_BUILD_HOME="$HOME/crafter-build/share/crafter-build"
|
||||
|
||||
# --- aarch64 Alpine sysroot (unprivileged: apk.static --usermode)
|
||||
SYSROOT="$HOME/.cache/fingerprintd/sysroot-aarch64-alpine"
|
||||
|
|
|
|||
|
|
@ -23,14 +23,9 @@ MIRROR="${MIRROR:-https://dl-cdn.alpinelinux.org/alpine/edge}"
|
|||
ARCH=aarch64
|
||||
# gcc is in the list for its crtbeginS.o/libgcc: clang's driver for
|
||||
# *-alpine-linux-musl links against the GCC runtime it detects under
|
||||
# <sysroot>/usr/lib/gcc/<triple>/. llvm-runtimes is in it for the std module
|
||||
# source of this very libc++ (usr/share/libc++/v1/std.cppm; libc++-dev ships
|
||||
# none): crafter-build compiles the sysroot's own copy first. --upgrade below
|
||||
# is for a run over an existing sysroot: added alone beside an older libc++,
|
||||
# a newer llvm-runtimes' source does not compile against its headers
|
||||
# (imsd, 2026-10-04: 23.1.2 against 22.1.8); upgraded together, it does.
|
||||
# <sysroot>/usr/lib/gcc/<triple>/.
|
||||
# glib-dev is for the GDBus bus layer (net.reactivated.Fprint).
|
||||
PKGS="musl-dev libc++ libc++-dev llvm-runtimes glib-dev compiler-rt llvm-libunwind-dev gcc"
|
||||
PKGS="musl-dev libc++ libc++-dev glib-dev compiler-rt llvm-libunwind-dev gcc"
|
||||
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
|
|
@ -53,6 +48,6 @@ mkdir -p "$SYSROOT"
|
|||
--arch "$ARCH" --root "$SYSROOT" --initdb --no-scripts --no-cache \
|
||||
--usermode --keys-dir "$work/usr/share/apk/keys/$ARCH" \
|
||||
-X "$MIRROR/main" -X "$MIRROR/community" \
|
||||
add --upgrade $PKGS
|
||||
add $PKGS
|
||||
|
||||
echo ">> done: $SYSROOT"
|
||||
|
|
|
|||
Loading…
Reference in a new issue