Skip to content

test: add e2e package install tests for .deb and .rpm#23

Open
tyvsmith wants to merge 18 commits intomainfrom
test/e2e-package-install
Open

test: add e2e package install tests for .deb and .rpm#23
tyvsmith wants to merge 18 commits intomainfrom
test/e2e-package-install

Conversation

@tyvsmith
Copy link
Copy Markdown
Owner

@tyvsmith tyvsmith commented Apr 5, 2026

Summary

  • Add container-based e2e tests that build real packages and install them with the actual package manager (dpkg/dnf), closing the gap where existing test-deb/test-rpm only validated file layout from manually-installed binaries
  • Three new justfile recipes: test-deb-e2e (Ubuntu 24.04 legacy), test-deb-tpm-e2e (Debian trixie TPM), test-rpm-e2e (Fedora)
  • Uses host-built binaries so tests run in ~30s each — no Rust compilation in containers

What's tested end-to-end

  • Package construction (build-deb.sh / rpmbuild)
  • Package manager install (dpkg -i / dnf install)
  • postinst scripts, sysusers/tmpfiles triggers, dependency resolution
  • pkg-validate.sh checks (file layout, PAM symbols, D-Bus policy, binary execution)

Test plan

  • just test-deb-e2e — 16/16 passed
  • just test-deb-tpm-e2e — 16/16 passed
  • just test-rpm-e2e — 16/16 passed

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings April 5, 2026 20:44
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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 .rpm install validation.
  • Add an RPM helper script to build an RPM from prebuilt binaries (skipping Rust compilation).
  • Add just recipes 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.

Comment on lines +31 to +33
RUN bash /build/test/build-rpm-prebuilt.sh "0.0.0" && \
dnf install -y --disablerepo='*' ./*.rpm && \
rm -rf ~/rpmbuild ./*.rpm
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Comment thread test/Containerfile.deb-tpm-e2e Outdated
Comment on lines +15 to +17
libtss2-esys-3.0.2-0t64 \
libtss2-tctildr0t64 \
python3 \
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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" \

Copilot uses AI. Check for mistakes.
Comment thread test/Containerfile.rpm-e2e Outdated
Comment on lines +26 to +28
# 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
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
# 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"

Copilot uses AI. Check for mistakes.
# 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) && \
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
(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 && \

Copilot uses AI. Check for mistakes.
Comment thread test/Containerfile.deb-tpm-e2e Outdated
Comment on lines +40 to +41
(dpkg -i facelock_0.0.0-test-1_amd64.deb || true) && \
apt-get install -f -y && \
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
(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/* && \

Copilot uses AI. Check for mistakes.
tyvsmith and others added 16 commits April 5, 2026 13:51
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants