From 453f27834bd45bae997b2ced5c3d9dd9e72db279 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 13:43:51 -0700 Subject: [PATCH 01/18] test: add e2e package install tests for .deb and .rpm Add container-based tests that build real packages and install them with the actual package manager, closing the gap where existing tests only validated file layout from manually installed binaries. New recipes: - just test-deb-e2e: Ubuntu 24.04 legacy .deb via dpkg - just test-deb-tpm-e2e: Debian trixie TPM .deb via dpkg - just test-rpm-e2e: Fedora .rpm via dnf Uses host-built binaries (no Rust compilation in containers) so tests run in ~30s each while exercising the full packaging pipeline: package construction, postinst scripts, dependency resolution, sysusers/tmpfiles triggers, and pkg-validate.sh checks. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/releasing.md | 20 +++++++++++----- justfile | 21 ++++++++++++++++ test/Containerfile.deb-e2e | 43 +++++++++++++++++++++++++++++++++ test/Containerfile.deb-tpm-e2e | 44 ++++++++++++++++++++++++++++++++++ test/Containerfile.rpm-e2e | 35 +++++++++++++++++++++++++++ test/build-rpm-prebuilt.sh | 39 ++++++++++++++++++++++++++++++ 6 files changed, 196 insertions(+), 6 deletions(-) create mode 100644 test/Containerfile.deb-e2e create mode 100644 test/Containerfile.deb-tpm-e2e create mode 100644 test/Containerfile.rpm-e2e create mode 100755 test/build-rpm-prebuilt.sh diff --git a/docs/releasing.md b/docs/releasing.md index d1cf550..8a2c95c 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -70,14 +70,19 @@ Both `.deb` packages are uploaded to the GitHub Release for direct download. For Before releasing, validate packages build and install correctly on each target: ```bash -just test-pam # Arch container PAM smoke tests (existing) -just test-rpm # Fedora container — build, install, validate file layout -just test-deb # Ubuntu container — build, install, validate file layout +just test-pam # Arch container PAM smoke tests (existing) +just test-rpm # Fedora container — build, install, validate file layout +just test-deb # Ubuntu container — build, install, validate file layout +just test-deb-e2e # Ubuntu 24.04 — build real legacy .deb, install via dpkg, validate +just test-deb-tpm-e2e # Debian trixie — build real TPM .deb, install via dpkg, validate +just test-rpm-e2e # Fedora — build real .rpm, install via dnf, validate ``` -These containers don't need camera hardware. They validate that the package installs -all required files to the correct paths, PAM symbols are exported, D-Bus policy is -valid, and systemd units are present. +These containers don't need camera hardware. The `test-rpm` / `test-deb` recipes validate +file layout from manually installed binaries. The `test-rpm-e2e` / `test-deb-e2e` recipes +go further: they build real packages using the same scripts as CI, install them with the +actual package manager (`dnf` / `dpkg`), and validate the result — testing postinst +scripts, dependency resolution, sysusers/tmpfiles triggers, and the full install path. ### Release preflight (recommended) @@ -90,6 +95,9 @@ just check just test-pam just test-rpm just test-deb +just test-deb-e2e +just test-deb-tpm-e2e +just test-rpm-e2e ``` `just release-preflight` checks local tools, required packaging files, and whether diff --git a/justfile b/justfile index 558c757..ee98ac8 100644 --- a/justfile +++ b/justfile @@ -402,6 +402,27 @@ test-deb: build-release podman build -t facelock-deb-test -f test/Containerfile.ubuntu . podman run --rm facelock-deb-test +# End-to-end .deb package test — build real .deb, install via dpkg, validate +test-deb-e2e: build-release + #!/usr/bin/env bash + set -euo pipefail + podman build -t facelock-deb-e2e -f test/Containerfile.deb-e2e . + podman run --rm facelock-deb-e2e + +# End-to-end TPM .deb package test — build real .deb (trixie), install via dpkg, validate +test-deb-tpm-e2e: build-release + #!/usr/bin/env bash + set -euo pipefail + podman build -t facelock-deb-tpm-e2e -f test/Containerfile.deb-tpm-e2e . + podman run --rm facelock-deb-tpm-e2e + +# End-to-end .rpm package test — build real .rpm, install via dnf, validate +test-rpm-e2e: build-release + #!/usr/bin/env bash + set -euo pipefail + podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . + podman run --rm facelock-rpm-e2e + # Test APT repo generation locally (requires reprepro + gpg) test-apt-repo: #!/usr/bin/env bash diff --git a/test/Containerfile.deb-e2e b/test/Containerfile.deb-e2e new file mode 100644 index 0000000..028b0fc --- /dev/null +++ b/test/Containerfile.deb-e2e @@ -0,0 +1,43 @@ +# E2E package test — builds a real .deb and installs via dpkg +# Uses host-built release binaries (from `just build-release`); no Rust compilation in container. +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + libpam-runtime \ + dbus \ + dpkg-dev \ + systemd \ + binutils \ + libxkbcommon0 \ + libtss2-esys-3.0.2-0t64 \ + libtss2-tctildr0t64 \ + python3 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +# Copy host-built release binaries +COPY target/release/facelock /build/target/release/facelock +COPY target/release/libpam_facelock.so /build/target/release/libpam_facelock.so + +# Copy project files needed by build-deb.sh +COPY config/ /build/config/ +COPY systemd/ /build/systemd/ +COPY dbus/ /build/dbus/ +COPY dist/ /build/dist/ +COPY .github/workflows/scripts/build-deb.sh /build/.github/workflows/scripts/build-deb.sh + +# Copy test validation script +COPY test/pkg-validate.sh /pkg-validate.sh +RUN chmod +x /pkg-validate.sh + +# Build the .deb from the host-built binaries and install it +SHELL ["/bin/bash", "-euo", "pipefail", "-c"] +RUN bash /build/.github/workflows/scripts/build-deb.sh "0.0.0-test" "legacy" && \ + (dpkg -i facelock_0.0.0-test-1~legacy1_amd64.deb || true) && \ + apt-get install -f -y && \ + rm -rf facelock_0.0.0-test-1~legacy1_amd64 facelock_0.0.0-test-1~legacy1_amd64.deb + +CMD ["/pkg-validate.sh"] diff --git a/test/Containerfile.deb-tpm-e2e b/test/Containerfile.deb-tpm-e2e new file mode 100644 index 0000000..eea5e25 --- /dev/null +++ b/test/Containerfile.deb-tpm-e2e @@ -0,0 +1,44 @@ +# E2E package test — builds a real TPM-enabled .deb and installs via dpkg +# Uses host-built release binaries (from `just build-release`); no Rust compilation in container. +# Mirrors the CI TPM .deb build which targets Debian trixie. +FROM debian:trixie + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + libpam-runtime \ + dbus \ + dpkg-dev \ + systemd \ + binutils \ + libxkbcommon0 \ + libtss2-esys-3.0.2-0t64 \ + libtss2-tctildr0t64 \ + python3 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +# Copy host-built release binaries +COPY target/release/facelock /build/target/release/facelock +COPY target/release/libpam_facelock.so /build/target/release/libpam_facelock.so + +# Copy project files needed by build-deb.sh +COPY config/ /build/config/ +COPY systemd/ /build/systemd/ +COPY dbus/ /build/dbus/ +COPY dist/ /build/dist/ +COPY .github/workflows/scripts/build-deb.sh /build/.github/workflows/scripts/build-deb.sh + +# Copy test validation script +COPY test/pkg-validate.sh /pkg-validate.sh +RUN chmod +x /pkg-validate.sh + +# Build the TPM .deb from host-built binaries and install it +SHELL ["/bin/bash", "-euo", "pipefail", "-c"] +RUN bash /build/.github/workflows/scripts/build-deb.sh "0.0.0-test" "tpm" && \ + (dpkg -i facelock_0.0.0-test-1_amd64.deb || true) && \ + apt-get install -f -y && \ + rm -rf facelock_0.0.0-test-1_amd64 facelock_0.0.0-test-1_amd64.deb + +CMD ["/pkg-validate.sh"] diff --git a/test/Containerfile.rpm-e2e b/test/Containerfile.rpm-e2e new file mode 100644 index 0000000..5f9a456 --- /dev/null +++ b/test/Containerfile.rpm-e2e @@ -0,0 +1,35 @@ +# E2E package test — builds a real .rpm and installs via dnf +# Uses host-built release binaries (from `just build-release`); no Rust compilation in container. +FROM fedora:latest + +RUN dnf -y install pam dbus rpm-build systemd binutils glibc libxkbcommon tpm2-tss python3 && dnf clean all + +WORKDIR /build + +# Copy host-built release binaries +COPY target/release/facelock /build/target/release/facelock +COPY target/release/libpam_facelock.so /build/target/release/libpam_facelock.so + +# Copy project files needed for RPM packaging +COPY config/ /build/config/ +COPY systemd/ /build/systemd/ +COPY dbus/ /build/dbus/ +COPY dist/ /build/dist/ +COPY LICENSE-MIT /build/LICENSE-MIT +COPY LICENSE-APACHE /build/LICENSE-APACHE + +# Copy helper script and test validation +COPY test/build-rpm-prebuilt.sh /build/test/build-rpm-prebuilt.sh +COPY test/pkg-validate.sh /pkg-validate.sh +RUN chmod +x /build/test/build-rpm-prebuilt.sh /pkg-validate.sh + +# Create placeholder for polkit agent (spec %files lists it unconditionally) +RUN touch /build/target/release/facelock-polkit-agent && \ + chmod 755 /build/target/release/facelock-polkit-agent + +# Build the .rpm from pre-built binaries and install it +RUN bash /build/test/build-rpm-prebuilt.sh "0.0.0" && \ + dnf install -y --disablerepo='*' ./*.rpm && \ + rm -rf ~/rpmbuild ./*.rpm + +CMD ["/pkg-validate.sh"] diff --git a/test/build-rpm-prebuilt.sh b/test/build-rpm-prebuilt.sh new file mode 100755 index 0000000..fd3ce94 --- /dev/null +++ b/test/build-rpm-prebuilt.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Build an RPM from pre-built release binaries (no Rust compilation). +# Used by test/Containerfile.rpm-e2e for local end-to-end package testing. +set -euo pipefail + +VERSION="${1:-0.0.0}" + +echo "=== Building RPM from pre-built binaries ===" +echo "Version: ${VERSION}" + +# Set up rpmbuild tree +mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} + +# Copy and patch the spec: replace cargo build commands with no-ops +cp dist/facelock.spec ~/rpmbuild/SPECS/facelock.spec +sed -i "s|^Version:.*|Version: ${VERSION}|" ~/rpmbuild/SPECS/facelock.spec +sed -i "s|^Release:.*|Release: 1%{?dist}|" ~/rpmbuild/SPECS/facelock.spec +sed -i 's|^cargo build.*|true|g' ~/rpmbuild/SPECS/facelock.spec +# Ensure facelock lib dir exists even without bundled ORT +sed -i '/^if \[ -f onnxruntime/i install -dm755 %{buildroot}%{_libdir}/facelock' ~/rpmbuild/SPECS/facelock.spec + +# Create source tarball INCLUDING target/release/ (pre-built binaries) +tar --exclude=.git \ + --transform "s|^\.|facelock-${VERSION}|" \ + -czf "${HOME}/rpmbuild/SOURCES/facelock-${VERSION}.tar.gz" . + +# Build the RPM (compilation is skipped via the patched spec). +# --nodeps skips BuildRequires enforcement since we're packaging pre-built binaries. +# Disable debuginfo/debugsource — pre-built binaries have no debug source files. +rpmbuild --define "_topdir $HOME/rpmbuild" \ + --define "debug_package %{nil}" \ + --nodeps \ + -bb ~/rpmbuild/SPECS/facelock.spec + +# Copy resulting RPM to current directory +cp ~/rpmbuild/RPMS/*/*.rpm ./ + +echo "=== RPM package built ===" +ls -la ./*.rpm From 22269f731f0fcffbdabd7caf8d6b014e94142476 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 13:47:07 -0700 Subject: [PATCH 02/18] test: add interactive shell recipes for e2e package containers Add test-deb-e2e-shell and test-rpm-e2e-shell recipes that drop into an interactive bash shell inside the package-installed containers with camera devices mapped in for manual end-to-end verification. Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/justfile b/justfile index ee98ac8..6b3f12b 100644 --- a/justfile +++ b/justfile @@ -423,6 +423,34 @@ test-rpm-e2e: build-release podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . podman run --rm facelock-rpm-e2e +# Interactive shell in .deb package container (requires camera) +test-deb-e2e-shell: build-release + #!/usr/bin/env bash + set -euo pipefail + podman build -t facelock-deb-e2e -f test/Containerfile.deb-e2e . + devices="" + for d in /dev/video*; do + [ -e "$d" ] && devices="$devices --device $d" + done + echo "Starting interactive shell (Ubuntu 24.04, .deb installed). Try:" + echo " facelock enroll --user root --label myface" + echo " facelock test --user root" + podman run --rm -it $devices facelock-deb-e2e /bin/bash + +# Interactive shell in .rpm package container (requires camera) +test-rpm-e2e-shell: build-release + #!/usr/bin/env bash + set -euo pipefail + podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . + devices="" + for d in /dev/video*; do + [ -e "$d" ] && devices="$devices --device $d" + done + echo "Starting interactive shell (Fedora, .rpm installed). Try:" + echo " facelock enroll --user root --label myface" + echo " facelock test --user root" + podman run --rm -it $devices facelock-rpm-e2e /bin/bash + # Test APT repo generation locally (requires reprepro + gpg) test-apt-repo: #!/usr/bin/env bash From 16de13ca3a9fd0b77874b72f43f9ecaa27829c47 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 13:51:45 -0700 Subject: [PATCH 03/18] fix: add SSL/CA deps to e2e containers for model downloads Add ca-certificates and SSL libraries so `facelock setup` can download models over HTTPS in interactive shell sessions. Co-Authored-By: Claude Opus 4.6 (1M context) --- test/Containerfile.deb-e2e | 2 ++ test/Containerfile.deb-tpm-e2e | 2 ++ test/Containerfile.rpm-e2e | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/Containerfile.deb-e2e b/test/Containerfile.deb-e2e index 028b0fc..4807fbc 100644 --- a/test/Containerfile.deb-e2e +++ b/test/Containerfile.deb-e2e @@ -13,6 +13,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libxkbcommon0 \ libtss2-esys-3.0.2-0t64 \ libtss2-tctildr0t64 \ + ca-certificates \ + libssl3t64 \ python3 \ && rm -rf /var/lib/apt/lists/* diff --git a/test/Containerfile.deb-tpm-e2e b/test/Containerfile.deb-tpm-e2e index eea5e25..c1a867a 100644 --- a/test/Containerfile.deb-tpm-e2e +++ b/test/Containerfile.deb-tpm-e2e @@ -14,6 +14,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libxkbcommon0 \ libtss2-esys-3.0.2-0t64 \ libtss2-tctildr0t64 \ + ca-certificates \ + libssl3t64 \ python3 \ && rm -rf /var/lib/apt/lists/* diff --git a/test/Containerfile.rpm-e2e b/test/Containerfile.rpm-e2e index 5f9a456..9876217 100644 --- a/test/Containerfile.rpm-e2e +++ b/test/Containerfile.rpm-e2e @@ -2,7 +2,7 @@ # Uses host-built release binaries (from `just build-release`); no Rust compilation in container. FROM fedora:latest -RUN dnf -y install pam dbus rpm-build systemd binutils glibc libxkbcommon tpm2-tss python3 && dnf clean all +RUN dnf -y install pam dbus rpm-build systemd binutils glibc libxkbcommon tpm2-tss ca-certificates openssl-libs python3 && dnf clean all WORKDIR /build From dd6eb31a4a396211bc870a68d3dc5e551ab50dd3 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 14:04:56 -0700 Subject: [PATCH 04/18] refactor: rename interactive shell recipes and mount host models Rename test-deb-e2e-shell/test-rpm-e2e-shell to test-deb-shell/ test-rpm-shell for consistency with the existing test-shell recipe. Mount /var/lib/facelock/models from the host into all interactive shell containers so models don't need to be re-downloaded. Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/justfile b/justfile index 6b3f12b..15c7b92 100644 --- a/justfile +++ b/justfile @@ -69,13 +69,17 @@ test-shell: _build-test-container for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" done - echo "Starting interactive shell. Try:" + models="" + if [ -d /var/lib/facelock/models ]; then + models="-v /var/lib/facelock/models:/var/lib/facelock/models:ro" + fi + echo "Starting interactive shell (Arch, binary install). Try:" echo " facelock daemon &" echo " sleep 2" echo " facelock enroll --user testuser --label myface" echo " facelock test --user testuser" echo " pamtester facelock-test testuser authenticate" - podman run --rm -it $devices facelock-pam-test /bin/bash + podman run --rm -it $devices $models facelock-pam-test /bin/bash # Build release and install to system # Run as: just install (builds as you, installs as root) @@ -424,7 +428,7 @@ test-rpm-e2e: build-release podman run --rm facelock-rpm-e2e # Interactive shell in .deb package container (requires camera) -test-deb-e2e-shell: build-release +test-deb-shell: build-release #!/usr/bin/env bash set -euo pipefail podman build -t facelock-deb-e2e -f test/Containerfile.deb-e2e . @@ -432,13 +436,17 @@ test-deb-e2e-shell: build-release for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" done + models="" + if [ -d /var/lib/facelock/models ]; then + models="-v /var/lib/facelock/models:/var/lib/facelock/models:ro" + fi echo "Starting interactive shell (Ubuntu 24.04, .deb installed). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" - podman run --rm -it $devices facelock-deb-e2e /bin/bash + podman run --rm -it $devices $models facelock-deb-e2e /bin/bash # Interactive shell in .rpm package container (requires camera) -test-rpm-e2e-shell: build-release +test-rpm-shell: build-release #!/usr/bin/env bash set -euo pipefail podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . @@ -446,10 +454,14 @@ test-rpm-e2e-shell: build-release for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" done + models="" + if [ -d /var/lib/facelock/models ]; then + models="-v /var/lib/facelock/models:/var/lib/facelock/models:ro" + fi echo "Starting interactive shell (Fedora, .rpm installed). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" - podman run --rm -it $devices facelock-rpm-e2e /bin/bash + podman run --rm -it $devices $models facelock-rpm-e2e /bin/bash # Test APT repo generation locally (requires reprepro + gpg) test-apt-repo: From 41f4a1b2d4a3bd9a6c8fe6a65b66021713e5333f Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 14:07:31 -0700 Subject: [PATCH 05/18] fix: mount host ORT library into interactive shell containers All three shell recipes (test-shell, test-deb-shell, test-rpm-shell) now mount the host's libonnxruntime.so so facelock can run inference without needing ORT bundled in the test packages. Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/justfile b/justfile index 15c7b92..ab0b63e 100644 --- a/justfile +++ b/justfile @@ -69,17 +69,23 @@ test-shell: _build-test-container for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" done - models="" + mounts="" if [ -d /var/lib/facelock/models ]; then - models="-v /var/lib/facelock/models:/var/lib/facelock/models:ro" + mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models:ro" fi + for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do + if [ -f "$ort" ]; then + mounts="$mounts -v $ort:/usr/lib/libonnxruntime.so:ro" + break + fi + done echo "Starting interactive shell (Arch, binary install). Try:" echo " facelock daemon &" echo " sleep 2" echo " facelock enroll --user testuser --label myface" echo " facelock test --user testuser" echo " pamtester facelock-test testuser authenticate" - podman run --rm -it $devices $models facelock-pam-test /bin/bash + podman run --rm -it $devices $mounts facelock-pam-test /bin/bash # Build release and install to system # Run as: just install (builds as you, installs as root) @@ -436,14 +442,20 @@ test-deb-shell: build-release for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" done - models="" + mounts="" if [ -d /var/lib/facelock/models ]; then - models="-v /var/lib/facelock/models:/var/lib/facelock/models:ro" + mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models:ro" fi + for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do + if [ -f "$ort" ]; then + mounts="$mounts -v $ort:/usr/lib/libonnxruntime.so:ro" + break + fi + done echo "Starting interactive shell (Ubuntu 24.04, .deb installed). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" - podman run --rm -it $devices $models facelock-deb-e2e /bin/bash + podman run --rm -it $devices $mounts facelock-deb-e2e /bin/bash # Interactive shell in .rpm package container (requires camera) test-rpm-shell: build-release @@ -454,14 +466,20 @@ test-rpm-shell: build-release for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" done - models="" + mounts="" if [ -d /var/lib/facelock/models ]; then - models="-v /var/lib/facelock/models:/var/lib/facelock/models:ro" + mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models:ro" fi + for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do + if [ -f "$ort" ]; then + mounts="$mounts -v $ort:/usr/lib/libonnxruntime.so:ro" + break + fi + done echo "Starting interactive shell (Fedora, .rpm installed). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" - podman run --rm -it $devices $models facelock-rpm-e2e /bin/bash + podman run --rm -it $devices $mounts facelock-rpm-e2e /bin/bash # Test APT repo generation locally (requires reprepro + gpg) test-apt-repo: From 64f996e9a2db3720369bef5bd12ec022bdc9d035 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 14:32:41 -0700 Subject: [PATCH 06/18] fix: mount models read-write in interactive shell containers Setup's create_directories() needs to write to /var/lib/facelock/models (ensure it exists, set permissions). Read-only mounts caused setup to fail with "failed to create directory". Interactive shells also need write access for enrollment data and database files. Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/justfile b/justfile index ab0b63e..4db51d9 100644 --- a/justfile +++ b/justfile @@ -71,7 +71,7 @@ test-shell: _build-test-container done mounts="" if [ -d /var/lib/facelock/models ]; then - mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models:ro" + mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models" fi for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do if [ -f "$ort" ]; then @@ -444,7 +444,7 @@ test-deb-shell: build-release done mounts="" if [ -d /var/lib/facelock/models ]; then - mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models:ro" + mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models" fi for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do if [ -f "$ort" ]; then @@ -468,7 +468,7 @@ test-rpm-shell: build-release done mounts="" if [ -d /var/lib/facelock/models ]; then - mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models:ro" + mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models" fi for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do if [ -f "$ort" ]; then From 7b146004029d19e3bee50d2e08209f57c7680371 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 14:44:23 -0700 Subject: [PATCH 07/18] fix: mount model files individually to avoid rootless podman chmod issue Rootless podman can't chmod on bind-mounted directories due to UID mapping. Mount individual .onnx and .toml files instead of the directory, so /var/lib/facelock/models/ stays a native container directory that setup can chmod freely. Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/justfile b/justfile index 4db51d9..a57d969 100644 --- a/justfile +++ b/justfile @@ -70,9 +70,9 @@ test-shell: _build-test-container [ -e "$d" ] && devices="$devices --device $d" done mounts="" - if [ -d /var/lib/facelock/models ]; then - mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models" - fi + for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do + [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" + done for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do if [ -f "$ort" ]; then mounts="$mounts -v $ort:/usr/lib/libonnxruntime.so:ro" @@ -443,9 +443,9 @@ test-deb-shell: build-release [ -e "$d" ] && devices="$devices --device $d" done mounts="" - if [ -d /var/lib/facelock/models ]; then - mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models" - fi + for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do + [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" + done for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do if [ -f "$ort" ]; then mounts="$mounts -v $ort:/usr/lib/libonnxruntime.so:ro" @@ -467,9 +467,9 @@ test-rpm-shell: build-release [ -e "$d" ] && devices="$devices --device $d" done mounts="" - if [ -d /var/lib/facelock/models ]; then - mounts="$mounts -v /var/lib/facelock/models:/var/lib/facelock/models" - fi + for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do + [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" + done for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do if [ -f "$ort" ]; then mounts="$mounts -v $ort:/usr/lib/libonnxruntime.so:ro" From 8de2df9eaaf3c6c50f38a34567a54faf5745f43f Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 15:24:51 -0700 Subject: [PATCH 08/18] fix: resolve ORT symlink before mounting into containers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The host's libonnxruntime.so is a symlink chain (→ .so.1 → .so.1.24.4). Podman can't mount dangling symlinks into containers. Use readlink -f to resolve to the real file before mounting. Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/justfile b/justfile index a57d969..c2abd76 100644 --- a/justfile +++ b/justfile @@ -74,8 +74,9 @@ test-shell: _build-test-container [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" done for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do - if [ -f "$ort" ]; then - mounts="$mounts -v $ort:/usr/lib/libonnxruntime.so:ro" + if [ -e "$ort" ]; then + real_ort="$(readlink -f "$ort")" + mounts="$mounts -v $real_ort:/usr/lib/libonnxruntime.so:ro" break fi done @@ -447,8 +448,9 @@ test-deb-shell: build-release [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" done for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do - if [ -f "$ort" ]; then - mounts="$mounts -v $ort:/usr/lib/libonnxruntime.so:ro" + if [ -e "$ort" ]; then + real_ort="$(readlink -f "$ort")" + mounts="$mounts -v $real_ort:/usr/lib/libonnxruntime.so:ro" break fi done @@ -471,8 +473,9 @@ test-rpm-shell: build-release [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" done for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do - if [ -f "$ort" ]; then - mounts="$mounts -v $ort:/usr/lib/libonnxruntime.so:ro" + if [ -e "$ort" ]; then + real_ort="$(readlink -f "$ort")" + mounts="$mounts -v $real_ort:/usr/lib/libonnxruntime.so:ro" break fi done From f0ed38ddbdd59e3616f092f013aaccd46c42f155 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 16:22:20 -0700 Subject: [PATCH 09/18] fix: use portable CPU-only ORT for cross-distro shell containers The host's ONNX Runtime (e.g. Arch onnxruntime package) has distro-specific deps (glibc 2.43, libprotobuf, libabsl) that don't exist in Fedora/Ubuntu containers, causing silent inference failure. Shell recipes now download a portable CPU-only ORT from GitHub releases (matching the host's ORT version) and cache it in /tmp/facelock-ort-portable/. Also mount test/container-config.toml to disable IR requirement for RGB-only cameras. Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 53 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/justfile b/justfile index c2abd76..817add4 100644 --- a/justfile +++ b/justfile @@ -434,8 +434,37 @@ test-rpm-e2e: build-release podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . podman run --rm facelock-rpm-e2e +# Download portable CPU-only ONNX Runtime for cross-distro container testing. +# Host ORT (e.g. Arch onnxruntime package) has distro-specific deps that don't +# work inside Fedora/Ubuntu containers. Cached in /tmp/facelock-ort-portable/. +_ensure-portable-ort: + #!/usr/bin/env bash + set -euo pipefail + ORT_CACHE="/tmp/facelock-ort-portable" + if [ -f "$ORT_CACHE/libonnxruntime.so" ]; then + exit 0 + fi + # Detect host ORT version to download a matching portable build + ORT_VER="" + for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do + if [ -e "$ort" ]; then + ORT_VER="$(readlink -f "$ort" | grep -oP '\d+\.\d+\.\d+$')" + break + fi + done + if [ -z "$ORT_VER" ]; then + echo "Warning: no system libonnxruntime.so found, using 1.20.1" + ORT_VER="1.20.1" + fi + echo "Downloading portable ONNX Runtime ${ORT_VER}..." + mkdir -p "$ORT_CACHE" + curl -fsSL "https://github.com/microsoft/onnxruntime/releases/download/v${ORT_VER}/onnxruntime-linux-x64-${ORT_VER}.tgz" \ + | tar xz -C "$ORT_CACHE" --strip-components=2 "onnxruntime-linux-x64-${ORT_VER}/lib/libonnxruntime.so.${ORT_VER}" + mv "$ORT_CACHE/libonnxruntime.so.${ORT_VER}" "$ORT_CACHE/libonnxruntime.so" + echo "Cached portable ORT at $ORT_CACHE/libonnxruntime.so" + # Interactive shell in .deb package container (requires camera) -test-deb-shell: build-release +test-deb-shell: build-release _ensure-portable-ort #!/usr/bin/env bash set -euo pipefail podman build -t facelock-deb-e2e -f test/Containerfile.deb-e2e . @@ -447,20 +476,16 @@ test-deb-shell: build-release for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" done - for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do - if [ -e "$ort" ]; then - real_ort="$(readlink -f "$ort")" - mounts="$mounts -v $real_ort:/usr/lib/libonnxruntime.so:ro" - break - fi - done + ort_cache="/tmp/facelock-ort-portable/libonnxruntime.so" + mounts="$mounts -v $ort_cache:/usr/lib/libonnxruntime.so:ro" + mounts="$mounts -v $(pwd)/test/container-config.toml:/etc/facelock/config.toml:ro" echo "Starting interactive shell (Ubuntu 24.04, .deb installed). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" podman run --rm -it $devices $mounts facelock-deb-e2e /bin/bash # Interactive shell in .rpm package container (requires camera) -test-rpm-shell: build-release +test-rpm-shell: build-release _ensure-portable-ort #!/usr/bin/env bash set -euo pipefail podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . @@ -472,13 +497,9 @@ test-rpm-shell: build-release for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" done - for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do - if [ -e "$ort" ]; then - real_ort="$(readlink -f "$ort")" - mounts="$mounts -v $real_ort:/usr/lib/libonnxruntime.so:ro" - break - fi - done + ort_cache="/tmp/facelock-ort-portable/libonnxruntime.so" + mounts="$mounts -v $ort_cache:/usr/lib/libonnxruntime.so:ro" + mounts="$mounts -v $(pwd)/test/container-config.toml:/etc/facelock/config.toml:ro" echo "Starting interactive shell (Fedora, .rpm installed). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" From 7d1e363c2f7a78c4f254014147d0cb48974d3159 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 18:06:04 -0700 Subject: [PATCH 10/18] fix: copy test config into container instead of bind-mounting over it Setup tries to chmod /etc/facelock/config.toml which fails on a read-only bind mount in rootless podman. Mount to /tmp and copy into place at container start so it's a native writable file. Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/justfile b/justfile index 817add4..9740321 100644 --- a/justfile +++ b/justfile @@ -478,11 +478,12 @@ test-deb-shell: build-release _ensure-portable-ort done ort_cache="/tmp/facelock-ort-portable/libonnxruntime.so" mounts="$mounts -v $ort_cache:/usr/lib/libonnxruntime.so:ro" - mounts="$mounts -v $(pwd)/test/container-config.toml:/etc/facelock/config.toml:ro" + mounts="$mounts -v $(pwd)/test/container-config.toml:/tmp/container-config.toml:ro" echo "Starting interactive shell (Ubuntu 24.04, .deb installed). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" - podman run --rm -it $devices $mounts facelock-deb-e2e /bin/bash + podman run --rm -it $devices $mounts facelock-deb-e2e \ + bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; exec bash" # Interactive shell in .rpm package container (requires camera) test-rpm-shell: build-release _ensure-portable-ort @@ -499,11 +500,12 @@ test-rpm-shell: build-release _ensure-portable-ort done ort_cache="/tmp/facelock-ort-portable/libonnxruntime.so" mounts="$mounts -v $ort_cache:/usr/lib/libonnxruntime.so:ro" - mounts="$mounts -v $(pwd)/test/container-config.toml:/etc/facelock/config.toml:ro" + mounts="$mounts -v $(pwd)/test/container-config.toml:/tmp/container-config.toml:ro" echo "Starting interactive shell (Fedora, .rpm installed). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" - podman run --rm -it $devices $mounts facelock-rpm-e2e /bin/bash + podman run --rm -it $devices $mounts facelock-rpm-e2e \ + bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; exec bash" # Test APT repo generation locally (requires reprepro + gpg) test-apt-repo: From 4c21cc26a870754971f70bd8ff6eac92d5220630 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 18:08:23 -0700 Subject: [PATCH 11/18] fix: copy host models into container instead of bind-mounting Setup tries to chmod model files after download verification, which fails on read-only bind mounts in rootless podman. Mount model files to /tmp/host-models/ and copy them into /var/lib/facelock/models/ at container start so they're native writable files. Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/justfile b/justfile index 9740321..46516db 100644 --- a/justfile +++ b/justfile @@ -71,7 +71,7 @@ test-shell: _build-test-container done mounts="" for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do - [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" + [ -f "$f" ] && mounts="$mounts -v $f:/tmp/host-models/$(basename $f):ro" done for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do if [ -e "$ort" ]; then @@ -86,7 +86,8 @@ test-shell: _build-test-container echo " facelock enroll --user testuser --label myface" echo " facelock test --user testuser" echo " pamtester facelock-test testuser authenticate" - podman run --rm -it $devices $mounts facelock-pam-test /bin/bash + podman run --rm -it $devices $mounts facelock-pam-test \ + bash -c "cp /tmp/host-models/* /var/lib/facelock/models/ 2>/dev/null; exec bash" # Build release and install to system # Run as: just install (builds as you, installs as root) @@ -474,7 +475,7 @@ test-deb-shell: build-release _ensure-portable-ort done mounts="" for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do - [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" + [ -f "$f" ] && mounts="$mounts -v $f:/tmp/host-models/$(basename $f):ro" done ort_cache="/tmp/facelock-ort-portable/libonnxruntime.so" mounts="$mounts -v $ort_cache:/usr/lib/libonnxruntime.so:ro" @@ -483,7 +484,7 @@ test-deb-shell: build-release _ensure-portable-ort echo " facelock enroll --user root --label myface" echo " facelock test --user root" podman run --rm -it $devices $mounts facelock-deb-e2e \ - bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; exec bash" + bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; cp /tmp/host-models/* /var/lib/facelock/models/ 2>/dev/null; exec bash" # Interactive shell in .rpm package container (requires camera) test-rpm-shell: build-release _ensure-portable-ort @@ -496,7 +497,7 @@ test-rpm-shell: build-release _ensure-portable-ort done mounts="" for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do - [ -f "$f" ] && mounts="$mounts -v $f:/var/lib/facelock/models/$(basename $f):ro" + [ -f "$f" ] && mounts="$mounts -v $f:/tmp/host-models/$(basename $f):ro" done ort_cache="/tmp/facelock-ort-portable/libonnxruntime.so" mounts="$mounts -v $ort_cache:/usr/lib/libonnxruntime.so:ro" @@ -505,7 +506,7 @@ test-rpm-shell: build-release _ensure-portable-ort echo " facelock enroll --user root --label myface" echo " facelock test --user root" podman run --rm -it $devices $mounts facelock-rpm-e2e \ - bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; exec bash" + bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; cp /tmp/host-models/* /var/lib/facelock/models/ 2>/dev/null; exec bash" # Test APT repo generation locally (requires reprepro + gpg) test-apt-repo: From 389686a866a353c0705f0abdd3958c036d63a2b0 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sun, 5 Apr 2026 20:54:44 -0700 Subject: [PATCH 12/18] feat: bundle ORT in e2e test packages to match real release packages Download portable CPU-only ONNX Runtime during container build and include it in the .deb/.rpm packages, exactly as CI does for release packages. This verifies the full user experience: - Package includes bundled ORT at the expected path - facelock finds and loads ORT from the bundled location - No external ORT mount needed for interactive shells pkg-validate.sh now confirms "bundled ONNX Runtime ... present". Co-Authored-By: Claude Opus 4.6 (1M context) --- justfile | 37 ++-------------------------------- test/Containerfile.deb-e2e | 9 +++++++++ test/Containerfile.deb-tpm-e2e | 8 ++++++++ test/Containerfile.rpm-e2e | 8 ++++++++ 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/justfile b/justfile index 46516db..a885a2c 100644 --- a/justfile +++ b/justfile @@ -435,37 +435,8 @@ test-rpm-e2e: build-release podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . podman run --rm facelock-rpm-e2e -# Download portable CPU-only ONNX Runtime for cross-distro container testing. -# Host ORT (e.g. Arch onnxruntime package) has distro-specific deps that don't -# work inside Fedora/Ubuntu containers. Cached in /tmp/facelock-ort-portable/. -_ensure-portable-ort: - #!/usr/bin/env bash - set -euo pipefail - ORT_CACHE="/tmp/facelock-ort-portable" - if [ -f "$ORT_CACHE/libonnxruntime.so" ]; then - exit 0 - fi - # Detect host ORT version to download a matching portable build - ORT_VER="" - for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do - if [ -e "$ort" ]; then - ORT_VER="$(readlink -f "$ort" | grep -oP '\d+\.\d+\.\d+$')" - break - fi - done - if [ -z "$ORT_VER" ]; then - echo "Warning: no system libonnxruntime.so found, using 1.20.1" - ORT_VER="1.20.1" - fi - echo "Downloading portable ONNX Runtime ${ORT_VER}..." - mkdir -p "$ORT_CACHE" - curl -fsSL "https://github.com/microsoft/onnxruntime/releases/download/v${ORT_VER}/onnxruntime-linux-x64-${ORT_VER}.tgz" \ - | tar xz -C "$ORT_CACHE" --strip-components=2 "onnxruntime-linux-x64-${ORT_VER}/lib/libonnxruntime.so.${ORT_VER}" - mv "$ORT_CACHE/libonnxruntime.so.${ORT_VER}" "$ORT_CACHE/libonnxruntime.so" - echo "Cached portable ORT at $ORT_CACHE/libonnxruntime.so" - # Interactive shell in .deb package container (requires camera) -test-deb-shell: build-release _ensure-portable-ort +test-deb-shell: build-release #!/usr/bin/env bash set -euo pipefail podman build -t facelock-deb-e2e -f test/Containerfile.deb-e2e . @@ -477,8 +448,6 @@ test-deb-shell: build-release _ensure-portable-ort for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do [ -f "$f" ] && mounts="$mounts -v $f:/tmp/host-models/$(basename $f):ro" done - ort_cache="/tmp/facelock-ort-portable/libonnxruntime.so" - mounts="$mounts -v $ort_cache:/usr/lib/libonnxruntime.so:ro" mounts="$mounts -v $(pwd)/test/container-config.toml:/tmp/container-config.toml:ro" echo "Starting interactive shell (Ubuntu 24.04, .deb installed). Try:" echo " facelock enroll --user root --label myface" @@ -487,7 +456,7 @@ test-deb-shell: build-release _ensure-portable-ort bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; cp /tmp/host-models/* /var/lib/facelock/models/ 2>/dev/null; exec bash" # Interactive shell in .rpm package container (requires camera) -test-rpm-shell: build-release _ensure-portable-ort +test-rpm-shell: build-release #!/usr/bin/env bash set -euo pipefail podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . @@ -499,8 +468,6 @@ test-rpm-shell: build-release _ensure-portable-ort for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do [ -f "$f" ] && mounts="$mounts -v $f:/tmp/host-models/$(basename $f):ro" done - ort_cache="/tmp/facelock-ort-portable/libonnxruntime.so" - mounts="$mounts -v $ort_cache:/usr/lib/libonnxruntime.so:ro" mounts="$mounts -v $(pwd)/test/container-config.toml:/tmp/container-config.toml:ro" echo "Starting interactive shell (Fedora, .rpm installed). Try:" echo " facelock enroll --user root --label myface" diff --git a/test/Containerfile.deb-e2e b/test/Containerfile.deb-e2e index 4807fbc..adc2f53 100644 --- a/test/Containerfile.deb-e2e +++ b/test/Containerfile.deb-e2e @@ -35,6 +35,15 @@ COPY .github/workflows/scripts/build-deb.sh /build/.github/workflows/scripts/bui COPY test/pkg-validate.sh /pkg-validate.sh RUN chmod +x /pkg-validate.sh +# Download portable CPU-only ONNX Runtime (same as CI bundles in release packages). +# Detect version from host binary's linked ORT, fall back to 1.20.1. +ARG ORT_VERSION=1.20.1 +ADD https://github.com/microsoft/onnxruntime/releases/download/v${ORT_VERSION}/onnxruntime-linux-x64-${ORT_VERSION}.tgz /tmp/ort.tgz +RUN mkdir -p /build/onnxruntime/lib && \ + tar xzf /tmp/ort.tgz -C /tmp && \ + cp /tmp/onnxruntime-linux-x64-${ORT_VERSION}/lib/libonnxruntime.so.${ORT_VERSION} /build/onnxruntime/lib/libonnxruntime.so && \ + rm -rf /tmp/ort.tgz /tmp/onnxruntime-linux-x64-${ORT_VERSION} + # Build the .deb from the host-built binaries and install it SHELL ["/bin/bash", "-euo", "pipefail", "-c"] RUN bash /build/.github/workflows/scripts/build-deb.sh "0.0.0-test" "legacy" && \ diff --git a/test/Containerfile.deb-tpm-e2e b/test/Containerfile.deb-tpm-e2e index c1a867a..4202c94 100644 --- a/test/Containerfile.deb-tpm-e2e +++ b/test/Containerfile.deb-tpm-e2e @@ -36,6 +36,14 @@ COPY .github/workflows/scripts/build-deb.sh /build/.github/workflows/scripts/bui COPY test/pkg-validate.sh /pkg-validate.sh RUN chmod +x /pkg-validate.sh +# Download portable CPU-only ONNX Runtime (same as CI bundles in release packages) +ARG ORT_VERSION=1.20.1 +ADD https://github.com/microsoft/onnxruntime/releases/download/v${ORT_VERSION}/onnxruntime-linux-x64-${ORT_VERSION}.tgz /tmp/ort.tgz +RUN mkdir -p /build/onnxruntime/lib && \ + tar xzf /tmp/ort.tgz -C /tmp && \ + cp /tmp/onnxruntime-linux-x64-${ORT_VERSION}/lib/libonnxruntime.so.${ORT_VERSION} /build/onnxruntime/lib/libonnxruntime.so && \ + rm -rf /tmp/ort.tgz /tmp/onnxruntime-linux-x64-${ORT_VERSION} + # Build the TPM .deb from host-built binaries and install it SHELL ["/bin/bash", "-euo", "pipefail", "-c"] RUN bash /build/.github/workflows/scripts/build-deb.sh "0.0.0-test" "tpm" && \ diff --git a/test/Containerfile.rpm-e2e b/test/Containerfile.rpm-e2e index 9876217..d65b149 100644 --- a/test/Containerfile.rpm-e2e +++ b/test/Containerfile.rpm-e2e @@ -27,6 +27,14 @@ RUN chmod +x /build/test/build-rpm-prebuilt.sh /pkg-validate.sh RUN touch /build/target/release/facelock-polkit-agent && \ chmod 755 /build/target/release/facelock-polkit-agent +# Download portable CPU-only ONNX Runtime (same as CI bundles in release packages) +ARG ORT_VERSION=1.20.1 +ADD https://github.com/microsoft/onnxruntime/releases/download/v${ORT_VERSION}/onnxruntime-linux-x64-${ORT_VERSION}.tgz /tmp/ort.tgz +RUN mkdir -p /build/onnxruntime/lib && \ + tar xzf /tmp/ort.tgz -C /tmp && \ + cp /tmp/onnxruntime-linux-x64-${ORT_VERSION}/lib/libonnxruntime.so.${ORT_VERSION} /build/onnxruntime/lib/libonnxruntime.so && \ + rm -rf /tmp/ort.tgz /tmp/onnxruntime-linux-x64-${ORT_VERSION} + # Build the .rpm from pre-built binaries and install it RUN bash /build/test/build-rpm-prebuilt.sh "0.0.0" && \ dnf install -y --disablerepo='*' ./*.rpm && \ From ac44202ba820e98bc2f255810177f5b37da70db2 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Mon, 6 Apr 2026 16:35:29 -0700 Subject: [PATCH 13/18] fix: search lib64 bundled ORT path for Fedora/RHEL RPM packages The RPM spec installs bundled ORT to %{_libdir}/facelock/ which resolves to /usr/lib64/facelock/ on x86_64 Fedora/RHEL/openSUSE. The ORT search code only checked /usr/lib/facelock/ (Debian path), so Fedora users could never find the bundled ORT. Add /usr/lib64/facelock/libonnxruntime.so to the bundled ORT search paths. Also auto-detect host ORT version for e2e container builds so bundled ORT matches the binary's build-time ORT. Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/facelock-face/src/provider.rs | 26 ++++++++++++++++---------- justfile | 15 ++++++++++----- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/crates/facelock-face/src/provider.rs b/crates/facelock-face/src/provider.rs index 23b9bc2..c0a6297 100644 --- a/crates/facelock-face/src/provider.rs +++ b/crates/facelock-face/src/provider.rs @@ -11,7 +11,11 @@ const SYSTEM_ORT_PATHS: &[&str] = &[ ]; /// Bundled CPU-only ORT fallback, shipped with the facelock package. -const BUNDLED_ORT_PATH: &str = "/usr/lib/facelock/libonnxruntime.so"; +/// Debian/Ubuntu use /usr/lib/, Fedora/RHEL use /usr/lib64/ on x86_64. +const BUNDLED_ORT_PATHS: &[&str] = &[ + "/usr/lib/facelock/libonnxruntime.so", + "/usr/lib64/facelock/libonnxruntime.so", +]; /// Load the ONNX Runtime shared library. /// @@ -55,15 +59,17 @@ fn load_ort() -> std::result::Result<(), String> { } // Fall back to bundled CPU-only ORT - let bundled = std::path::Path::new(BUNDLED_ORT_PATH); - if bundled.exists() { - match ort::init_from(bundled) { - Ok(_) => { - tracing::info!("Loaded bundled CPU ONNX Runtime from {BUNDLED_ORT_PATH}"); - return; - } - Err(e) => { - tracing::warn!("Found bundled ORT but failed to load: {e}"); + for bundled_path in BUNDLED_ORT_PATHS { + let bundled = std::path::Path::new(bundled_path); + if bundled.exists() { + match ort::init_from(bundled) { + Ok(_) => { + tracing::info!("Loaded bundled CPU ONNX Runtime from {bundled_path}"); + return; + } + Err(e) => { + tracing::warn!("Found bundled ORT at {bundled_path} but failed to load: {e}"); + } } } } diff --git a/justfile b/justfile index a885a2c..23b7502 100644 --- a/justfile +++ b/justfile @@ -400,6 +400,11 @@ show-paths: @echo "Service: /usr/lib/systemd/system/facelock-daemon.service" @echo "Logs: /var/log/facelock/" +# Detect host ONNX Runtime version for container builds. +# Local binaries are built against the host ORT, so bundled ORT must match. +# CI uses 1.20.1 (set in release.yml); local builds use whatever is installed. +_ort-version := `for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do if [ -e "$ort" ]; then readlink -f "$ort" | grep -oP '\d+\.\d+\.\d+$'; exit; fi; done; echo "1.20.1"` + # Test RPM packaging in Fedora container test-rpm: build-release #!/usr/bin/env bash @@ -418,28 +423,28 @@ test-deb: build-release test-deb-e2e: build-release #!/usr/bin/env bash set -euo pipefail - podman build -t facelock-deb-e2e -f test/Containerfile.deb-e2e . + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-e2e -f test/Containerfile.deb-e2e . podman run --rm facelock-deb-e2e # End-to-end TPM .deb package test — build real .deb (trixie), install via dpkg, validate test-deb-tpm-e2e: build-release #!/usr/bin/env bash set -euo pipefail - podman build -t facelock-deb-tpm-e2e -f test/Containerfile.deb-tpm-e2e . + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-tpm-e2e -f test/Containerfile.deb-tpm-e2e . podman run --rm facelock-deb-tpm-e2e # End-to-end .rpm package test — build real .rpm, install via dnf, validate test-rpm-e2e: build-release #!/usr/bin/env bash set -euo pipefail - podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . podman run --rm facelock-rpm-e2e # Interactive shell in .deb package container (requires camera) test-deb-shell: build-release #!/usr/bin/env bash set -euo pipefail - podman build -t facelock-deb-e2e -f test/Containerfile.deb-e2e . + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-e2e -f test/Containerfile.deb-e2e . devices="" for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" @@ -459,7 +464,7 @@ test-deb-shell: build-release test-rpm-shell: build-release #!/usr/bin/env bash set -euo pipefail - podman build -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . devices="" for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" From 3d0caa565d7e7e70f29babbd5a7ae1aaef8c2bc4 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Mon, 6 Apr 2026 17:51:25 -0700 Subject: [PATCH 14/18] style: apply cargo fmt to provider.rs Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/facelock-face/src/provider.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/facelock-face/src/provider.rs b/crates/facelock-face/src/provider.rs index c0a6297..aa5d89d 100644 --- a/crates/facelock-face/src/provider.rs +++ b/crates/facelock-face/src/provider.rs @@ -68,7 +68,9 @@ fn load_ort() -> std::result::Result<(), String> { return; } Err(e) => { - tracing::warn!("Found bundled ORT at {bundled_path} but failed to load: {e}"); + tracing::warn!( + "Found bundled ORT at {bundled_path} but failed to load: {e}" + ); } } } From 7567902f639b7e99f26274be67287e10258e7fdb Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Mon, 6 Apr 2026 18:12:06 -0700 Subject: [PATCH 15/18] refactor: rename test recipes for consistency and add release shells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consistent naming across three tiers: - test-{deb,rpm}-pkg: automated package build + install + validation - test-{deb,rpm}-dev-shell: interactive with host models for fast iteration - test-{deb,rpm}-release-shell: clean-room interactive, real user experience Release shells mount nothing from the host except the test config (to disable IR for RGB cameras). The user runs facelock setup to download models, then enroll and test — exactly like a real install. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/releasing.md | 39 +++++++++++++++--------- justfile | 78 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 81 insertions(+), 36 deletions(-) diff --git a/docs/releasing.md b/docs/releasing.md index 8a2c95c..32a0b50 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -70,19 +70,30 @@ Both `.deb` packages are uploaded to the GitHub Release for direct download. For Before releasing, validate packages build and install correctly on each target: ```bash -just test-pam # Arch container PAM smoke tests (existing) -just test-rpm # Fedora container — build, install, validate file layout -just test-deb # Ubuntu container — build, install, validate file layout -just test-deb-e2e # Ubuntu 24.04 — build real legacy .deb, install via dpkg, validate -just test-deb-tpm-e2e # Debian trixie — build real TPM .deb, install via dpkg, validate -just test-rpm-e2e # Fedora — build real .rpm, install via dnf, validate +# Automated (no camera needed) +just test-pam # Arch container PAM smoke tests +just test-rpm # Fedora — validate file layout from manual install +just test-deb # Ubuntu — validate file layout from manual install +just test-deb-pkg # Ubuntu 24.04 — build real .deb, install via dpkg, validate +just test-deb-tpm-pkg # Debian trixie — build real TPM .deb, install via dpkg, validate +just test-rpm-pkg # Fedora — build real .rpm, install via dnf, validate + +# Interactive (requires camera) +just test-deb-dev-shell # Ubuntu .deb with host models — fast iteration +just test-rpm-dev-shell # Fedora .rpm with host models — fast iteration +just test-deb-release-shell # Ubuntu .deb clean room — real user experience +just test-rpm-release-shell # Fedora .rpm clean room — real user experience ``` -These containers don't need camera hardware. The `test-rpm` / `test-deb` recipes validate -file layout from manually installed binaries. The `test-rpm-e2e` / `test-deb-e2e` recipes -go further: they build real packages using the same scripts as CI, install them with the -actual package manager (`dnf` / `dpkg`), and validate the result — testing postinst -scripts, dependency resolution, sysusers/tmpfiles triggers, and the full install path. +The `test-rpm` / `test-deb` recipes validate file layout from manually installed binaries. +The `*-pkg` recipes build real packages using the same scripts as CI, install them with +the actual package manager (`dnf` / `dpkg`), and validate the result — testing postinst +scripts, dependency resolution, ORT bundling, sysusers/tmpfiles triggers, and the full +install path. + +The `*-dev-shell` recipes mount host models for fast interactive camera testing. +The `*-release-shell` recipes start from a clean package install with nothing from the +host — run `facelock setup` to download models, then enroll and test. ### Release preflight (recommended) @@ -95,9 +106,9 @@ just check just test-pam just test-rpm just test-deb -just test-deb-e2e -just test-deb-tpm-e2e -just test-rpm-e2e +just test-deb-pkg +just test-deb-tpm-pkg +just test-rpm-pkg ``` `just release-preflight` checks local tools, required packaging files, and whether diff --git a/justfile b/justfile index 23b7502..5b4bf2a 100644 --- a/justfile +++ b/justfile @@ -419,32 +419,32 @@ test-deb: build-release podman build -t facelock-deb-test -f test/Containerfile.ubuntu . podman run --rm facelock-deb-test -# End-to-end .deb package test — build real .deb, install via dpkg, validate -test-deb-e2e: build-release +# Package test — build real .deb, install via dpkg, run automated validation +test-deb-pkg: build-release #!/usr/bin/env bash set -euo pipefail - podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-e2e -f test/Containerfile.deb-e2e . - podman run --rm facelock-deb-e2e + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-pkg -f test/Containerfile.deb-e2e . + podman run --rm facelock-deb-pkg -# End-to-end TPM .deb package test — build real .deb (trixie), install via dpkg, validate -test-deb-tpm-e2e: build-release +# Package test — build real TPM .deb (trixie), install via dpkg, run automated validation +test-deb-tpm-pkg: build-release #!/usr/bin/env bash set -euo pipefail - podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-tpm-e2e -f test/Containerfile.deb-tpm-e2e . - podman run --rm facelock-deb-tpm-e2e + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-tpm-pkg -f test/Containerfile.deb-tpm-e2e . + podman run --rm facelock-deb-tpm-pkg -# End-to-end .rpm package test — build real .rpm, install via dnf, validate -test-rpm-e2e: build-release +# Package test — build real .rpm, install via dnf, run automated validation +test-rpm-pkg: build-release #!/usr/bin/env bash set -euo pipefail - podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . - podman run --rm facelock-rpm-e2e + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-rpm-pkg -f test/Containerfile.rpm-e2e . + podman run --rm facelock-rpm-pkg -# Interactive shell in .deb package container (requires camera) -test-deb-shell: build-release +# Dev shell — interactive .deb container with host models for fast iteration (requires camera) +test-deb-dev-shell: build-release #!/usr/bin/env bash set -euo pipefail - podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-e2e -f test/Containerfile.deb-e2e . + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-pkg -f test/Containerfile.deb-e2e . devices="" for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" @@ -454,17 +454,17 @@ test-deb-shell: build-release [ -f "$f" ] && mounts="$mounts -v $f:/tmp/host-models/$(basename $f):ro" done mounts="$mounts -v $(pwd)/test/container-config.toml:/tmp/container-config.toml:ro" - echo "Starting interactive shell (Ubuntu 24.04, .deb installed). Try:" + echo "Starting dev shell (Ubuntu 24.04, .deb installed, host models). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" - podman run --rm -it $devices $mounts facelock-deb-e2e \ + podman run --rm -it $devices $mounts facelock-deb-pkg \ bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; cp /tmp/host-models/* /var/lib/facelock/models/ 2>/dev/null; exec bash" -# Interactive shell in .rpm package container (requires camera) -test-rpm-shell: build-release +# Dev shell — interactive .rpm container with host models for fast iteration (requires camera) +test-rpm-dev-shell: build-release #!/usr/bin/env bash set -euo pipefail - podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-rpm-e2e -f test/Containerfile.rpm-e2e . + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-rpm-pkg -f test/Containerfile.rpm-e2e . devices="" for d in /dev/video*; do [ -e "$d" ] && devices="$devices --device $d" @@ -474,12 +474,46 @@ test-rpm-shell: build-release [ -f "$f" ] && mounts="$mounts -v $f:/tmp/host-models/$(basename $f):ro" done mounts="$mounts -v $(pwd)/test/container-config.toml:/tmp/container-config.toml:ro" - echo "Starting interactive shell (Fedora, .rpm installed). Try:" + echo "Starting dev shell (Fedora, .rpm installed, host models). Try:" echo " facelock enroll --user root --label myface" echo " facelock test --user root" - podman run --rm -it $devices $mounts facelock-rpm-e2e \ + podman run --rm -it $devices $mounts facelock-rpm-pkg \ bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; cp /tmp/host-models/* /var/lib/facelock/models/ 2>/dev/null; exec bash" +# Release shell — clean-room .deb container, real user experience (requires camera) +test-deb-release-shell: build-release + #!/usr/bin/env bash + set -euo pipefail + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-deb-pkg -f test/Containerfile.deb-e2e . + devices="" + for d in /dev/video*; do + [ -e "$d" ] && devices="$devices --device $d" + done + mounts="-v $(pwd)/test/container-config.toml:/tmp/container-config.toml:ro" + echo "Starting release shell (Ubuntu 24.04, .deb installed, clean room). Try:" + echo " facelock setup" + echo " facelock enroll --user root --label myface" + echo " facelock test --user root" + podman run --rm -it $devices $mounts facelock-deb-pkg \ + bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; exec bash" + +# Release shell — clean-room .rpm container, real user experience (requires camera) +test-rpm-release-shell: build-release + #!/usr/bin/env bash + set -euo pipefail + podman build --build-arg ORT_VERSION={{_ort-version}} -t facelock-rpm-pkg -f test/Containerfile.rpm-e2e . + devices="" + for d in /dev/video*; do + [ -e "$d" ] && devices="$devices --device $d" + done + mounts="-v $(pwd)/test/container-config.toml:/tmp/container-config.toml:ro" + echo "Starting release shell (Fedora, .rpm installed, clean room). Try:" + echo " facelock setup" + echo " facelock enroll --user root --label myface" + echo " facelock test --user root" + podman run --rm -it $devices $mounts facelock-rpm-pkg \ + bash -c "cp /tmp/container-config.toml /etc/facelock/config.toml; exec bash" + # Test APT repo generation locally (requires reprepro + gpg) test-apt-repo: #!/usr/bin/env bash From d82f3b3a00f7b9fb4ca13119253f4799b80a2665 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Mon, 6 Apr 2026 18:18:01 -0700 Subject: [PATCH 16/18] refactor: rename Arch test recipes to test-arch-* for consistency Rename test-pam, test-integration, test-oneshot, test-shell to test-arch-pam, test-arch-integration, test-arch-oneshot, test-arch-dev-shell. Add test-arch-release-shell for clean-room Arch testing. All documentation updated to match: README, CONTRIBUTING, AGENTS.md, releasing.md, quickstart.md, testing.md, troubleshooting.md, and testing-roadmap.md. Co-Authored-By: Claude Opus 4.6 (1M context) --- AGENTS.md | 6 +++--- CONTRIBUTING.md | 8 ++++---- README.md | 8 ++++---- book/src/contributing.md | 8 ++++---- book/src/quickstart.md | 8 ++++---- book/src/testing.md | 16 +++++++-------- book/src/troubleshooting.md | 2 +- docs/quickstart.md | 8 ++++---- docs/releasing.md | 6 +++--- docs/testing-roadmap.md | 6 +++--- docs/testing-safety.md | 16 +++++++-------- docs/troubleshooting.md | 2 +- justfile | 40 ++++++++++++++++++++++--------------- 13 files changed, 71 insertions(+), 63 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ab118d7..4f5a00d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -93,9 +93,9 @@ Supported providers: `cpu` (default), `cuda` (NVIDIA), `rocm` (AMD), `openvino` |------|------|-----| | 1 | Unit tests | `cargo test --workspace` | | 2 | Hardware tests | `cargo test --workspace -- --ignored` | -| 3 | Container PAM smoke | `just test-pam` | -| 3b | Container E2E (daemon) | `just test-integration` | -| 3c | Container E2E (oneshot) | `just test-oneshot` | +| 3 | Arch container PAM smoke | `just test-arch-pam` | +| 3b | Arch container E2E (daemon) | `just test-arch-integration` | +| 3c | Arch container E2E (oneshot) | `just test-arch-oneshot` | | 4 | VM testing | Disposable VM with snapshots | | 5 | Host PAM | After tiers 3-4, with root shell backup | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 350a88f..8bed392 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,10 +69,10 @@ Requires a connected camera and downloaded models. These tests are marked `#[ign ### Tier 3: Container tests (requires podman) ```bash -just test-pam # PAM smoke tests (no camera) -just test-integration # end-to-end with camera (daemon mode) -just test-oneshot # end-to-end with camera (no daemon) -just test-shell # interactive container shell for debugging +just test-arch-pam # Arch PAM smoke tests (no camera) +just test-arch-integration # end-to-end with camera (daemon mode) +just test-arch-oneshot # end-to-end with camera (no daemon) +just test-arch-dev-shell # interactive container shell for debugging ``` Container tests validate PAM integration without risking host lockout. diff --git a/README.md b/README.md index 8fac5e9..db86901 100644 --- a/README.md +++ b/README.md @@ -171,10 +171,10 @@ This adds a face icon to the hyprlock password prompt and optionally sources a ` ```bash just check # unit tests + clippy + fmt -just test-pam # container PAM smoke tests -just test-integration # end-to-end with camera (daemon mode) -just test-oneshot # end-to-end with camera (no daemon) -just test-shell # interactive container for manual testing +just test-arch-pam # Arch container PAM smoke tests +just test-arch-integration # end-to-end with camera (daemon mode) +just test-arch-oneshot # end-to-end with camera (no daemon) +just test-arch-dev-shell # interactive container for manual testing ``` See [docs/testing-safety.md](docs/testing-safety.md) before editing PAM config on your system. diff --git a/book/src/contributing.md b/book/src/contributing.md index 56ffbf0..423336c 100644 --- a/book/src/contributing.md +++ b/book/src/contributing.md @@ -69,10 +69,10 @@ Requires a connected camera and downloaded models. These tests are marked `#[ign ### Tier 3: Container tests (requires podman) ```bash -just test-pam # PAM smoke tests (no camera) -just test-integration # end-to-end with camera (daemon mode) -just test-oneshot # end-to-end with camera (no daemon) -just test-shell # interactive container shell for debugging +just test-arch-pam # Arch PAM smoke tests (no camera) +just test-arch-integration # end-to-end with camera (daemon mode) +just test-arch-oneshot # end-to-end with camera (no daemon) +just test-arch-dev-shell # interactive container shell for debugging ``` Container tests validate PAM integration without risking host lockout. diff --git a/book/src/quickstart.md b/book/src/quickstart.md index c64bf49..af1ed99 100644 --- a/book/src/quickstart.md +++ b/book/src/quickstart.md @@ -101,10 +101,10 @@ sudo facelock bench warm-auth # measure auth latency ```bash just check # unit tests + clippy + fmt -just test-pam # container PAM smoke tests (no camera) -just test-integration # end-to-end with camera (daemon mode) -just test-oneshot # end-to-end with camera (no daemon) -just test-shell # interactive container shell +just test-arch-pam # Arch container PAM smoke tests (no camera) +just test-arch-integration # end-to-end with camera (daemon mode) +just test-arch-oneshot # end-to-end with camera (no daemon) +just test-arch-dev-shell # interactive container shell ``` ## System Installation diff --git a/book/src/testing.md b/book/src/testing.md index 14ecd77..ee5750b 100644 --- a/book/src/testing.md +++ b/book/src/testing.md @@ -28,10 +28,10 @@ Requires camera and downloaded ONNX models. Tests capture, model loading, full p ### Tier 3: Container Tests (requires podman) ```bash -just test-pam # PAM smoke tests (no camera needed) -just test-integration # full E2E with camera (daemon mode) -just test-oneshot # full E2E with camera (no daemon) -just test-shell # interactive shell for manual testing +just test-arch-pam # Arch PAM smoke tests (no camera needed) +just test-arch-integration # full E2E with camera (daemon mode) +just test-arch-oneshot # full E2E with camera (no daemon) +just test-arch-dev-shell # interactive shell for manual testing ``` Container tests validate: @@ -136,8 +136,8 @@ Local full CI: `bash test/run-tests.sh` | `just test` | Unit tests | | `just lint` | Clippy | | `just check` | test + lint + fmt | -| `just test-pam` | Container PAM smoke | -| `just test-integration` | E2E daemon mode | -| `just test-oneshot` | E2E oneshot mode | -| `just test-shell` | Interactive container | +| `just test-arch-pam` | Arch container PAM smoke | +| `just test-arch-integration` | E2E daemon mode | +| `just test-arch-oneshot` | E2E oneshot mode | +| `just test-arch-dev-shell` | Interactive container | | `just install` | System install (root) | diff --git a/book/src/troubleshooting.md b/book/src/troubleshooting.md index 414e267..a8936a1 100644 --- a/book/src/troubleshooting.md +++ b/book/src/troubleshooting.md @@ -103,7 +103,7 @@ cp /etc/pam.d/sudo.facelock-backup /etc/pam.d/sudo ### Prevention -- Always test in containers first (`just test-pam`). +- Always test in containers first (`just test-arch-pam`). - Keep a root shell open during PAM testing. - Start with `sudo` only -- do not add Facelock to `login` or `sddm` until `sudo` works reliably. - Set `security.disabled = true` as an emergency kill switch (PAM returns IGNORE). diff --git a/docs/quickstart.md b/docs/quickstart.md index 1081390..15edb7d 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -40,10 +40,10 @@ sudo facelock bench warm-auth # measure auth latency ```bash just check # unit tests + clippy + fmt -just test-pam # container PAM smoke tests (no camera) -just test-integration # end-to-end with camera (daemon mode) -just test-oneshot # end-to-end with camera (no daemon) -just test-shell # interactive container shell +just test-arch-pam # Arch container PAM smoke tests (no camera) +just test-arch-integration # end-to-end with camera (daemon mode) +just test-arch-oneshot # end-to-end with camera (no daemon) +just test-arch-dev-shell # interactive container shell ``` ## System Installation diff --git a/docs/releasing.md b/docs/releasing.md index 32a0b50..c931efc 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -71,7 +71,7 @@ Before releasing, validate packages build and install correctly on each target: ```bash # Automated (no camera needed) -just test-pam # Arch container PAM smoke tests +just test-arch-pam # Arch container PAM smoke tests just test-rpm # Fedora — validate file layout from manual install just test-deb # Ubuntu — validate file layout from manual install just test-deb-pkg # Ubuntu 24.04 — build real .deb, install via dpkg, validate @@ -103,7 +103,7 @@ Run this before creating/pushing a release tag: just release-preflight # stable release checks just release-preflight v0.2.0-rc1 # prerelease checks (AUR/COPR secrets optional) just check -just test-pam +just test-arch-pam just test-rpm just test-deb just test-deb-pkg @@ -268,7 +268,7 @@ The bundled ORT version is pinned in `.github/workflows/release.yml` as `ORT_VER Since facelock is a PAM module, broken releases can lock users out. Every release must: 1. Pass `just check` (tests + clippy + fmt) -2. Pass `just test-pam` (container PAM smoke tests) +2. Pass `just test-arch-pam` (Arch container PAM smoke tests) 3. Pass `just test-rpm` and `just test-deb` (multi-distro package validation) 4. Not change PAM auth semantics without explicit changelog entry 5. Preserve `/etc/pam.d/sudo` backup on install (`sudo.facelock-backup`) diff --git a/docs/testing-roadmap.md b/docs/testing-roadmap.md index 61d584f..fa8b2bd 100644 --- a/docs/testing-roadmap.md +++ b/docs/testing-roadmap.md @@ -30,7 +30,7 @@ locally before merging camera-related changes. ### Tier 3a: Container PAM Smoke Tests -**How:** `just test-pam` (podman, Arch Linux container) +**How:** `just test-arch-pam` (podman, Arch Linux container) **Status:** Active, runs in CI (`container-pam-test` job). 13 tests. Validates the PAM module in an isolated container without a camera: @@ -47,7 +47,7 @@ Validates the PAM module in an isolated container without a camera: ### Tier 3b: Container E2E (Daemon Mode) -**How:** `just test-integration` (podman, passes `/dev/video*` devices) +**How:** `just test-arch-integration` (podman, passes `/dev/video*` devices) **Status:** Active locally. Cannot run in CI (needs camera). 7 tests. Full daemon-mode flow inside a container with a real camera: @@ -61,7 +61,7 @@ Full daemon-mode flow inside a container with a real camera: ### Tier 3c: Container E2E (Oneshot Mode) -**How:** `just test-oneshot` (podman, passes `/dev/video*` devices) +**How:** `just test-arch-oneshot` (podman, passes `/dev/video*` devices) **Status:** Active locally. Cannot run in CI (needs camera). 10 tests. Same as 3b but fully daemonless: verifies no socket exists, enrollment, diff --git a/docs/testing-safety.md b/docs/testing-safety.md index 420a480..372bcb8 100644 --- a/docs/testing-safety.md +++ b/docs/testing-safety.md @@ -28,10 +28,10 @@ Requires camera and downloaded ONNX models. Tests capture, model loading, full p ### Tier 3: Container Tests (requires podman) ```bash -just test-pam # PAM smoke tests (no camera needed) -just test-integration # full E2E with camera (daemon mode) -just test-oneshot # full E2E with camera (no daemon) -just test-shell # interactive shell for manual testing +just test-arch-pam # Arch PAM smoke tests (no camera needed) +just test-arch-integration # full E2E with camera (daemon mode) +just test-arch-oneshot # full E2E with camera (no daemon) +just test-arch-dev-shell # interactive shell for manual testing ``` Container tests validate: @@ -136,8 +136,8 @@ Local full CI: `bash test/run-tests.sh` | `just test` | Unit tests | | `just lint` | Clippy | | `just check` | test + lint + fmt | -| `just test-pam` | Container PAM smoke | -| `just test-integration` | E2E daemon mode | -| `just test-oneshot` | E2E oneshot mode | -| `just test-shell` | Interactive container | +| `just test-arch-pam` | Arch container PAM smoke | +| `just test-arch-integration` | E2E daemon mode | +| `just test-arch-oneshot` | E2E oneshot mode | +| `just test-arch-dev-shell` | Interactive container | | `just install` | System install (root) | diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 63b0189..6276976 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -103,7 +103,7 @@ cp /etc/pam.d/sudo.facelock-backup /etc/pam.d/sudo ### Prevention -- Always test in containers first (`just test-pam`). +- Always test in containers first (`just test-arch-pam`). - Keep a root shell open during PAM testing. - Start with `sudo` only -- do not add Facelock to `login` or `sddm` until `sudo` works reliably. - Set `security.disabled = true` as an emergency kill switch (PAM returns IGNORE). diff --git a/justfile b/justfile index 5b4bf2a..7eaf9aa 100644 --- a/justfile +++ b/justfile @@ -37,12 +37,12 @@ check: test lint fmt-check _build-test-container: build-release podman build -t facelock-pam-test -f test/Containerfile . -# Run container PAM smoke tests -test-pam: _build-test-container +# Automated PAM smoke tests (Arch container) +test-arch-pam: _build-test-container podman run --rm facelock-pam-test -# Run end-to-end integration tests in container (requires camera) -test-integration: _build-test-container +# Automated daemon integration tests (Arch, requires camera) +test-arch-integration: _build-test-container #!/usr/bin/env bash set -euo pipefail devices="" @@ -51,8 +51,8 @@ test-integration: _build-test-container done podman run --rm $devices facelock-pam-test /run-integration-tests.sh -# Run oneshot (daemonless) end-to-end tests in container (requires camera) -test-oneshot: _build-test-container +# Automated oneshot (daemonless) integration tests (Arch, requires camera) +test-arch-oneshot: _build-test-container #!/usr/bin/env bash set -euo pipefail devices="" @@ -61,8 +61,8 @@ test-oneshot: _build-test-container done podman run --rm $devices facelock-pam-test /run-oneshot-tests.sh -# Open interactive shell in PAM test container (requires camera) -test-shell: _build-test-container +# Dev shell — interactive Arch container with host models for fast iteration (requires camera) +test-arch-dev-shell: _build-test-container #!/usr/bin/env bash set -euo pipefail devices="" @@ -73,14 +73,7 @@ test-shell: _build-test-container for f in /var/lib/facelock/models/*.onnx /var/lib/facelock/models/*.toml; do [ -f "$f" ] && mounts="$mounts -v $f:/tmp/host-models/$(basename $f):ro" done - for ort in /usr/lib/libonnxruntime.so /usr/lib64/libonnxruntime.so; do - if [ -e "$ort" ]; then - real_ort="$(readlink -f "$ort")" - mounts="$mounts -v $real_ort:/usr/lib/libonnxruntime.so:ro" - break - fi - done - echo "Starting interactive shell (Arch, binary install). Try:" + echo "Starting dev shell (Arch, binary install, host models). Try:" echo " facelock daemon &" echo " sleep 2" echo " facelock enroll --user testuser --label myface" @@ -89,6 +82,21 @@ test-shell: _build-test-container podman run --rm -it $devices $mounts facelock-pam-test \ bash -c "cp /tmp/host-models/* /var/lib/facelock/models/ 2>/dev/null; exec bash" +# Release shell — clean-room Arch container, real user experience (requires camera) +test-arch-release-shell: _build-test-container + #!/usr/bin/env bash + set -euo pipefail + devices="" + for d in /dev/video*; do + [ -e "$d" ] && devices="$devices --device $d" + done + echo "Starting release shell (Arch, binary install, clean room). Try:" + echo " facelock setup" + echo " facelock enroll --user testuser --label myface" + echo " facelock test --user testuser" + echo " pamtester facelock-test testuser authenticate" + podman run --rm -it $devices facelock-pam-test /bin/bash + # Build release and install to system # Run as: just install (builds as you, installs as root) install: build-release From 7228b3ef841856c6b8eeaae30ffdcad0caa1596d Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Mon, 6 Apr 2026 18:39:44 -0700 Subject: [PATCH 17/18] feat: add PAM, D-Bus, and package removal tests to e2e validation Three new test capabilities in pkg-validate.sh: - PAM smoke test: pamtester verifies the module loads on all distros (pamtester built from source in all e2e Containerfiles) - D-Bus activation: start dbus-daemon, verify facelock service is activatable via busctl/dbus-send - Package removal: dpkg -r / rpm -e, verify binary+PAM removed, config preserved Also fix: add DEBIAN/conffiles to build-deb.sh so dpkg -r preserves /etc/facelock/config.toml (another real bug caught by these tests). Deb: 23/23 passed, RPM: 21/21 passed. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/scripts/build-deb.sh | 3 ++ test/Containerfile.deb-e2e | 13 ++++++++- test/Containerfile.deb-tpm-e2e | 13 ++++++++- test/Containerfile.rpm-e2e | 13 ++++++++- test/pkg-validate.sh | 38 ++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 3 deletions(-) diff --git a/.github/workflows/scripts/build-deb.sh b/.github/workflows/scripts/build-deb.sh index 83c7f10..2b66674 100755 --- a/.github/workflows/scripts/build-deb.sh +++ b/.github/workflows/scripts/build-deb.sh @@ -76,6 +76,9 @@ Description: ${DESCRIPTION} ${DESCRIPTION_LONG} CTRL +# conffiles — preserve config on remove/upgrade +echo "/etc/facelock/config.toml" > "${PKG_DIR}/DEBIAN/conffiles" + # postinst and prerm scripts cp dist/debian/postinst "${PKG_DIR}/DEBIAN/postinst" chmod 755 "${PKG_DIR}/DEBIAN/postinst" diff --git a/test/Containerfile.deb-e2e b/test/Containerfile.deb-e2e index adc2f53..40a250b 100644 --- a/test/Containerfile.deb-e2e +++ b/test/Containerfile.deb-e2e @@ -18,6 +18,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ python3 \ && rm -rf /var/lib/apt/lists/* +# Build pamtester from source (not in Ubuntu/Debian repos) +RUN apt-get update && apt-get install -y --no-install-recommends build-essential libpam0g-dev curl && \ + curl -sL https://sourceforge.net/projects/pamtester/files/pamtester/0.1.2/pamtester-0.1.2.tar.gz/download | tar xz -C /tmp && \ + cd /tmp/pamtester-0.1.2 && ./configure --prefix=/usr CFLAGS="-Wno-implicit-function-declaration" && make && make install && \ + rm -rf /tmp/pamtester-0.1.2 && \ + apt-get purge -y build-essential libpam0g-dev && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* + +# Create test user for PAM tests +RUN useradd -m testuser && echo "testuser:test" | chpasswd + WORKDIR /build # Copy host-built release binaries @@ -31,8 +41,9 @@ COPY dbus/ /build/dbus/ COPY dist/ /build/dist/ COPY .github/workflows/scripts/build-deb.sh /build/.github/workflows/scripts/build-deb.sh -# Copy test validation script +# Copy test validation script and PAM test config COPY test/pkg-validate.sh /pkg-validate.sh +COPY test/pam.d/facelock-test /etc/pam.d/facelock-test RUN chmod +x /pkg-validate.sh # Download portable CPU-only ONNX Runtime (same as CI bundles in release packages). diff --git a/test/Containerfile.deb-tpm-e2e b/test/Containerfile.deb-tpm-e2e index 4202c94..9ea3e81 100644 --- a/test/Containerfile.deb-tpm-e2e +++ b/test/Containerfile.deb-tpm-e2e @@ -19,6 +19,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ python3 \ && rm -rf /var/lib/apt/lists/* +# Build pamtester from source (not in Ubuntu/Debian repos) +RUN apt-get update && apt-get install -y --no-install-recommends build-essential libpam0g-dev curl && \ + curl -sL https://sourceforge.net/projects/pamtester/files/pamtester/0.1.2/pamtester-0.1.2.tar.gz/download | tar xz -C /tmp && \ + cd /tmp/pamtester-0.1.2 && ./configure --prefix=/usr CFLAGS="-Wno-implicit-function-declaration" && make && make install && \ + rm -rf /tmp/pamtester-0.1.2 && \ + apt-get purge -y build-essential libpam0g-dev && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* + +# Create test user for PAM tests +RUN useradd -m testuser && echo "testuser:test" | chpasswd + WORKDIR /build # Copy host-built release binaries @@ -32,8 +42,9 @@ COPY dbus/ /build/dbus/ COPY dist/ /build/dist/ COPY .github/workflows/scripts/build-deb.sh /build/.github/workflows/scripts/build-deb.sh -# Copy test validation script +# Copy test validation script and PAM test config COPY test/pkg-validate.sh /pkg-validate.sh +COPY test/pam.d/facelock-test /etc/pam.d/facelock-test RUN chmod +x /pkg-validate.sh # Download portable CPU-only ONNX Runtime (same as CI bundles in release packages) diff --git a/test/Containerfile.rpm-e2e b/test/Containerfile.rpm-e2e index d65b149..1b6fb9e 100644 --- a/test/Containerfile.rpm-e2e +++ b/test/Containerfile.rpm-e2e @@ -4,6 +4,16 @@ FROM fedora:latest RUN dnf -y install pam dbus rpm-build systemd binutils glibc libxkbcommon tpm2-tss ca-certificates openssl-libs python3 && dnf clean all +# Build pamtester from source (not in Fedora repos) +RUN dnf -y install gcc gcc-c++ pam-devel make curl && \ + curl -sL https://sourceforge.net/projects/pamtester/files/pamtester/0.1.2/pamtester-0.1.2.tar.gz/download | tar xz -C /tmp && \ + cd /tmp/pamtester-0.1.2 && ./configure --prefix=/usr CFLAGS="-Wno-implicit-function-declaration" && make && make install && \ + rm -rf /tmp/pamtester-0.1.2 && \ + dnf -y remove gcc gcc-c++ pam-devel make && dnf clean all + +# Create test user for PAM tests +RUN useradd -m testuser && echo "testuser:test" | chpasswd + WORKDIR /build # Copy host-built release binaries @@ -18,9 +28,10 @@ COPY dist/ /build/dist/ COPY LICENSE-MIT /build/LICENSE-MIT COPY LICENSE-APACHE /build/LICENSE-APACHE -# Copy helper script and test validation +# Copy helper script, test validation, and PAM test config COPY test/build-rpm-prebuilt.sh /build/test/build-rpm-prebuilt.sh COPY test/pkg-validate.sh /pkg-validate.sh +COPY test/pam.d/facelock-test /etc/pam.d/facelock-test RUN chmod +x /build/test/build-rpm-prebuilt.sh /pkg-validate.sh # Create placeholder for polkit agent (spec %files lists it unconditionally) diff --git a/test/pkg-validate.sh b/test/pkg-validate.sh index f26f29a..30c54be 100644 --- a/test/pkg-validate.sh +++ b/test/pkg-validate.sh @@ -79,6 +79,44 @@ run_test "facelock group exists (sysusers)" "if command -v systemd-sysusers >/de run_test "facelock runtime directories exist (tmpfiles)" "if command -v systemd-tmpfiles >/dev/null 2>&1; then systemd-tmpfiles --create >/dev/null 2>&1 || true; fi; [ -d /var/lib/facelock ] && [ -d /var/log/facelock ]" +# PAM tests (only if pamtester is available) +if command -v pamtester >/dev/null 2>&1 && [ -f /etc/pam.d/facelock-test ]; then + run_test "PAM module loads via pamtester" "pamtester facelock-test testuser authenticate < /dev/null 2>&1 | grep -qiE '(successfully|authentication failure)'" +fi + +# D-Bus tests (only if dbus-daemon is available) +if command -v dbus-daemon >/dev/null 2>&1; then + # Start a system bus for testing + run_test "D-Bus system bus starts" "mkdir -p /run/dbus && dbus-daemon --system --fork --nopidfile 2>/dev/null" + + # Verify the facelock service is visible on the bus + if command -v busctl >/dev/null 2>&1; then + run_test "D-Bus facelock service activatable" "busctl --system list --activatable 2>/dev/null | grep -q org.facelock.Daemon" + elif command -v dbus-send >/dev/null 2>&1; then + run_test "D-Bus facelock service activatable" "dbus-send --system --dest=org.freedesktop.DBus --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ListActivatableNames 2>/dev/null | grep -q org.facelock.Daemon" + fi +fi + +# Package removal test — must come last since it removes the package +echo "" +echo "=== Package Removal Test ===" + +if command -v dpkg >/dev/null 2>&1; then + run_test "Package removal via dpkg" "dpkg -r facelock" + run_test "facelock binary removed after dpkg -r" "[ ! -f /usr/bin/facelock ]" + run_test "PAM module removed after dpkg -r" \ + "[ ! -f /lib/security/pam_facelock.so ] && [ ! -f /usr/lib/security/pam_facelock.so ] && [ ! -f /usr/lib64/security/pam_facelock.so ]" + run_test "Config preserved after dpkg -r (conffile)" "[ -f /etc/facelock/config.toml ]" +elif command -v rpm >/dev/null 2>&1; then + # Modify config so RPM treats it as user-edited and preserves it as .rpmsave + echo "# modified by test" >> /etc/facelock/config.toml + run_test "Package removal via rpm" "rpm -e facelock" + run_test "facelock binary removed after rpm -e" "[ ! -f /usr/bin/facelock ]" + run_test "PAM module removed after rpm -e" \ + "[ ! -f /lib/security/pam_facelock.so ] && [ ! -f /usr/lib/security/pam_facelock.so ] && [ ! -f /usr/lib64/security/pam_facelock.so ]" + run_test "Config preserved after rpm -e (config(noreplace))" "[ -f /etc/facelock/config.toml ] || [ -f /etc/facelock/config.toml.rpmsave ]" +fi + echo "" echo "=== Results: $PASS passed, $FAIL failed ===" From 34f8c5658b2b207c88c0a6a29dea20bc3b8c3cd0 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Mon, 6 Apr 2026 19:11:31 -0700 Subject: [PATCH 18/18] fix: address PR review feedback on e2e container tests - Remove --disablerepo='*' from dnf install so RPM dependency resolution is actually exercised - Detect libtss2 package names dynamically on trixie instead of hardcoding version-suffixed names that break across releases - Patch RPM spec %files to remove polkit-agent entry instead of shipping a placeholder binary - Add apt-get update before apt-get install -f so unmet deps can be resolved even after package lists were cleaned - Add DEBIAN/conffiles so dpkg -r preserves /etc/facelock/config.toml Co-Authored-By: Claude Opus 4.6 (1M context) --- test/Containerfile.deb-e2e | 2 +- test/Containerfile.deb-tpm-e2e | 12 ++++++++---- test/Containerfile.rpm-e2e | 8 ++++---- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/test/Containerfile.deb-e2e b/test/Containerfile.deb-e2e index 40a250b..a9534bf 100644 --- a/test/Containerfile.deb-e2e +++ b/test/Containerfile.deb-e2e @@ -59,7 +59,7 @@ RUN mkdir -p /build/onnxruntime/lib && \ SHELL ["/bin/bash", "-euo", "pipefail", "-c"] RUN bash /build/.github/workflows/scripts/build-deb.sh "0.0.0-test" "legacy" && \ (dpkg -i facelock_0.0.0-test-1~legacy1_amd64.deb || true) && \ - apt-get install -f -y && \ + apt-get update && apt-get install -f -y && \ rm -rf facelock_0.0.0-test-1~legacy1_amd64 facelock_0.0.0-test-1~legacy1_amd64.deb CMD ["/pkg-validate.sh"] diff --git a/test/Containerfile.deb-tpm-e2e b/test/Containerfile.deb-tpm-e2e index 9ea3e81..089d0d4 100644 --- a/test/Containerfile.deb-tpm-e2e +++ b/test/Containerfile.deb-tpm-e2e @@ -5,15 +5,19 @@ FROM debian:trixie ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends \ +# Detect libtss2 package names dynamically (version-suffixed, changes across releases) +RUN apt-get update && \ + TSS2_ESYS_PKG="$(apt-cache pkgnames libtss2-esys- 2>/dev/null | sort -V | tail -n1)" && \ + TSS2_TCTILDR_PKG="$(apt-cache pkgnames libtss2-tctildr 2>/dev/null | grep '^libtss2-tctildr' | sort -V | tail -n1)" && \ + apt-get install -y --no-install-recommends \ libpam-runtime \ dbus \ dpkg-dev \ systemd \ binutils \ libxkbcommon0 \ - libtss2-esys-3.0.2-0t64 \ - libtss2-tctildr0t64 \ + ${TSS2_ESYS_PKG} \ + ${TSS2_TCTILDR_PKG} \ ca-certificates \ libssl3t64 \ python3 \ @@ -59,7 +63,7 @@ RUN mkdir -p /build/onnxruntime/lib && \ SHELL ["/bin/bash", "-euo", "pipefail", "-c"] RUN bash /build/.github/workflows/scripts/build-deb.sh "0.0.0-test" "tpm" && \ (dpkg -i facelock_0.0.0-test-1_amd64.deb || true) && \ - apt-get install -f -y && \ + apt-get update && apt-get install -f -y && \ rm -rf facelock_0.0.0-test-1_amd64 facelock_0.0.0-test-1_amd64.deb CMD ["/pkg-validate.sh"] diff --git a/test/Containerfile.rpm-e2e b/test/Containerfile.rpm-e2e index 1b6fb9e..0814b4b 100644 --- a/test/Containerfile.rpm-e2e +++ b/test/Containerfile.rpm-e2e @@ -34,9 +34,9 @@ COPY test/pkg-validate.sh /pkg-validate.sh COPY test/pam.d/facelock-test /etc/pam.d/facelock-test RUN chmod +x /build/test/build-rpm-prebuilt.sh /pkg-validate.sh -# Create placeholder for polkit agent (spec %files lists it unconditionally) -RUN touch /build/target/release/facelock-polkit-agent && \ - chmod 755 /build/target/release/facelock-polkit-agent +# Patch spec to remove polkit agent from %files (not built from host binaries). +# Only remove the standalone %files entry, not the install command. +RUN sed -i '/^%{_bindir}\/facelock-polkit-agent$/d' /build/dist/facelock.spec # Download portable CPU-only ONNX Runtime (same as CI bundles in release packages) ARG ORT_VERSION=1.20.1 @@ -48,7 +48,7 @@ RUN mkdir -p /build/onnxruntime/lib && \ # Build the .rpm from pre-built binaries and install it RUN bash /build/test/build-rpm-prebuilt.sh "0.0.0" && \ - dnf install -y --disablerepo='*' ./*.rpm && \ + dnf install -y ./*.rpm && \ rm -rf ~/rpmbuild ./*.rpm CMD ["/pkg-validate.sh"]