test: add e2e package install tests for .deb and .rpm#23
test: add e2e package install tests for .deb and .rpm#23
Conversation
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds container-based end-to-end packaging tests that build real .deb/.rpm artifacts from host-built release binaries, install them via the native package manager (dpkg/dnf), and validate the resulting system install using the existing pkg-validate.sh checks. This complements the existing container tests that validate layout from manually installed binaries.
Changes:
- Add new e2e Containerfiles for legacy
.deb, TPM.deb, and.rpminstall validation. - Add an RPM helper script to build an RPM from prebuilt binaries (skipping Rust compilation).
- Add
justrecipes and release documentation updates to run the new e2e packaging checks locally.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
test/Containerfile.deb-e2e |
Builds/installs a legacy .deb in Ubuntu 24.04 and runs pkg-validate.sh. |
test/Containerfile.deb-tpm-e2e |
Builds/installs a TPM .deb in Debian trixie and runs pkg-validate.sh. |
test/Containerfile.rpm-e2e |
Builds/installs an .rpm in Fedora using prebuilt binaries and runs pkg-validate.sh. |
test/build-rpm-prebuilt.sh |
Patches the RPM spec to skip compilation and builds an RPM from the container’s pre-copied artifacts. |
justfile |
Adds test-deb-e2e, test-deb-tpm-e2e, and test-rpm-e2e recipes. |
docs/releasing.md |
Documents the new e2e pre-release validation commands. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| RUN bash /build/test/build-rpm-prebuilt.sh "0.0.0" && \ | ||
| dnf install -y --disablerepo='*' ./*.rpm && \ | ||
| rm -rf ~/rpmbuild ./*.rpm |
There was a problem hiding this comment.
dnf install is run with --disablerepo='*', which prevents dnf from resolving and fetching any missing dependencies from repos. That means this e2e flow doesn't actually exercise dependency resolution as described (it will only work if every required runtime dep is already preinstalled in the image). Consider removing --disablerepo (or adjust the documentation/expectations if the intent is to avoid networked dependency resolution).
| libtss2-esys-3.0.2-0t64 \ | ||
| libtss2-tctildr0t64 \ | ||
| python3 \ |
There was a problem hiding this comment.
This container installs version-specific libtss2 runtime packages (libtss2-esys-3.0.2-0t64, libtss2-tctildr0t64). On Debian trixie these package names/versions are likely to change over time, making the e2e test brittle. Consider installing a less version-pinned runtime dependency (e.g., a stable virtual/unversioned package name) or using a small detection step similar to the release workflow’s dynamic libtss2-esys* lookup.
| libtss2-esys-3.0.2-0t64 \ | |
| libtss2-tctildr0t64 \ | |
| python3 \ | |
| python3 \ | |
| && TSS2_ESYS_PKG="$(apt-cache pkgnames libtss2-esys- | grep '^libtss2-esys-' | sort -V | tail -n1)" \ | |
| && TSS2_TCTILDR_PKG="$(apt-cache pkgnames libtss2-tctildr | grep '^libtss2-tctildr' | sort -V | tail -n1)" \ | |
| && test -n "$TSS2_ESYS_PKG" \ | |
| && test -n "$TSS2_TCTILDR_PKG" \ | |
| && apt-get install -y --no-install-recommends "$TSS2_ESYS_PKG" "$TSS2_TCTILDR_PKG" \ |
| # 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 |
There was a problem hiding this comment.
Creating and installing a placeholder facelock-polkit-agent means the resulting RPM contains a dummy executable and the e2e test won’t detect if the real polkit agent artifact is missing. A more robust approach is to patch the spec during the prebuilt build (e.g., conditionally omit the %{_bindir}/facelock-polkit-agent entry in %files or mark it optional) rather than shipping a fake binary.
| # 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 the RPM spec for the prebuilt e2e build so it does not package | |
| # facelock-polkit-agent when that artifact is not present. | |
| RUN spec_file="$(find /build/dist -maxdepth 1 -type f -name '*.spec' | head -n 1)" && \ | |
| test -n "$spec_file" && \ | |
| sed -i '\|%{_bindir}/facelock-polkit-agent|d' "$spec_file" |
| # 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) && \ |
There was a problem hiding this comment.
apt-get install -f -y runs in a later layer after /var/lib/apt/lists/* was removed in the earlier apt-get install layer. If dpkg ever introduces unmet deps that need fetching, apt-get -f may fail without package lists. Consider running apt-get update immediately before apt-get install -f -y, or postpone cleaning /var/lib/apt/lists/* until after the fixup step.
| (dpkg -i facelock_0.0.0-test-1~legacy1_amd64.deb || true) && \ | |
| (dpkg -i facelock_0.0.0-test-1~legacy1_amd64.deb || true) && \ | |
| apt-get update && \ |
| (dpkg -i facelock_0.0.0-test-1_amd64.deb || true) && \ | ||
| apt-get install -f -y && \ |
There was a problem hiding this comment.
apt-get install -f -y runs in a later layer after /var/lib/apt/lists/* was removed in the earlier apt-get install layer. If dpkg ever introduces unmet deps that need fetching, apt-get -f may fail without package lists. Consider running apt-get update immediately before apt-get install -f -y, or postpone cleaning /var/lib/apt/lists/* until after the fixup step.
| (dpkg -i facelock_0.0.0-test-1_amd64.deb || true) && \ | |
| apt-get install -f -y && \ | |
| (dpkg -i facelock_0.0.0-test-1_amd64.deb || true) && \ | |
| apt-get update && \ | |
| apt-get install -f -y && \ | |
| rm -rf /var/lib/apt/lists/* && \ |
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
- 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) <noreply@anthropic.com>
Summary
dpkg/dnf), closing the gap where existingtest-deb/test-rpmonly validated file layout from manually-installed binariestest-deb-e2e(Ubuntu 24.04 legacy),test-deb-tpm-e2e(Debian trixie TPM),test-rpm-e2e(Fedora)What's tested end-to-end
build-deb.sh/rpmbuild)dpkg -i/dnf install)pkg-validate.shchecks (file layout, PAM symbols, D-Bus policy, binary execution)Test plan
just test-deb-e2e— 16/16 passedjust test-deb-tpm-e2e— 16/16 passedjust test-rpm-e2e— 16/16 passed🤖 Generated with Claude Code