Skip to content

feat: desktop dual-stack PAM routing, virtual fprintd D-Bus bridge, and disconnect cancellation - #128

Open
Lolle2000la wants to merge 54 commits into
mainfrom
feat/desktop-dual-stack-and-mock-fprintd
Open

feat: desktop dual-stack PAM routing, virtual fprintd D-Bus bridge, and disconnect cancellation#128
Lolle2000la wants to merge 54 commits into
mainfrom
feat/desktop-dual-stack-and-mock-fprintd

Conversation

@Lolle2000la

@Lolle2000la Lolle2000la commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Summary

This PR implements the comprehensive Desktop & Lock Screen Integration Plan (v5), resolving timeout and keyring issues across modern Linux desktop environments (KDE Plasma, GNOME, Sway, SDDM, GDM), alongside native distribution packaging and expanded multi-distro End-to-End (E2E) testing.

1. PAM Context-Aware Routing & Mode 3 (Dual-Stack Secondary)

  • Context Classification: Added classify_pam_context() in client-pam.
  • Dual-Stack Secondary Services: Secondary biometric PAM services (kde-fingerprint, gdm-fingerprint, kde-smartcard, fingerprint-auth) receive the full 120s timeout without blocking the main password conversation.
  • Non-Decisive Fallback: Non-interactive/unconfigured states return PAM_AUTHINFO_UNAVAIL, cleanly failing non-decisively so display managers and lock screens can display password fields or hide biometric indicators when no keys/transports are configured.
  • Decisive Success Flag: Decisive control flags auth [success=done default=bad] pam_tapauth.so ensure biometric authentication success immediately unlocks the session and bypasses subsequent password prompts while preserving standard account and session management.
  • Display Manager Login Bypass: sddm, gdm, lightdm, and plasmalogin are bypassed immediately with PAM_IGNORE at the login greeter so password-based login can automatically unlock cryptographic secret stores (gnome-keyring, kwallet).

2. Hard-Cancellation on Client Socket Disconnect

  • tapauthd's IPC connection handler runs authentication concurrently with a socket readability / EOF watcher.
  • When a lock screen worker exits on password entry (e.g. kscreenlocker_worker via qApp->quit()), the socket closes, immediately triggering the cancel registry to abort in-flight BLE and UDP discovery tasks and broadcast AuthenticationCancel to paired devices.

3. Virtual fprintd D-Bus Bridge

  • Embedded virtual net.reactivated.Fprint Manager and Device D-Bus services in tapauthd (enable_fprintd_bridge = true in /etc/tapauth/config.toml or runtime GUI toggle).
  • Implements ListEnrolledFingers, Claim (with sender D-Bus disconnect tracking and auto-release), Release, VerifyStart (handling "any"), VerifyStop, and VerifyStatus signals.
  • Transparently interfaces with GNOME Shell and KDE Plasma lock screens without requiring real fingerprint hardware.

4. GDM Initial Login vs. Lock Screen Probe

  • Queries systemd-logind (org.freedesktop.login1) for LockedHint == true on the user's graphical session.
  • Bypasses gdm-fingerprint at the initial login greeter to preserve password keyring auto-unlock, while activating TapAuth during screen lock.

5. Native Packaging & Distro Scriptlet Hardening

  • Debian / Ubuntu (.deb): Added packaging/debian/ with tapauth and tapauth-fprintd packages, dynamic PAM stack rewiring in postinst, clean prerm restoration on removal/purge, DEP-5 copyright, and eliminated workflow heredoc drift.
  • Fedora (.rpm): Updated packaging/tapauth.spec with %sysusers_create_compat in %pre, D-Bus policies in /usr/share/dbus-1/system.d/, ready-made authselect vendor profiles (tapauth and tapauth-sssd) with patched fingerprint-auth templates, and automated rollback in %preun.
  • Arch Linux (AUR): Hardened packaging/arch/ and packaging/arch-git/, added a libalpm hook (tapauth-fprintd-pam.hook) to maintain PAM bridge routing across desktop environment upgrades, fixed simultaneous uninstall ordering, eliminated .pacnew churn by shipping config.toml.example, and updated .SRCINFO.
  • Cross-Distro: Shipped virtual fprintd D-Bus activation files in dedicated opt-in tapauth-fprintd subpackages (enabling lock screen integration and runtime GUI toggle), hardened PAM stack rewiring and removal scriptlets across all distros, and updated INSTALLATION.md with group onboarding and migration instructions.

🧪 Expanded Multi-Distro End-to-End (E2E) Testing

Existing E2E Baseline (Prior to this PR)

TapAuth already had an automated E2E harness (scripts/test-e2e.sh) paired with a live Android emulator in CI that validated:

  • Local TCP pairing and QR code parameter parsing (Phase 1).
  • Basic UDP authentication grants, denials, rate limiting, and replay protections (Phases 2a–2e).
  • Virtual Bluetooth Low Energy (BLE) authentication via Bumble VHCI and BlueZ (Phases 3 & 4).

However, this baseline had two key limitations:

  1. Targeted In-Tree Debug Binaries Only: It only ran cargo build debug binaries directly out of target/debug/ with dev environment overrides (TAPAUTH_STATE_DIR, manual sockets) on the Ubuntu CI host. It did not test shipped, production-compiled binaries, system paths (/usr/bin/tapauthd, /usr/lib/security/pam_tapauth.so), or systemd socket activation.
  2. Lacked Desktop & Packaging Coverage: It did not cover the new desktop lock screen features (socket disconnect hard-cancellation, virtual fprintd D-Bus bridge, secondary PAM routing), nor did it validate behavior across other target distributions (Fedora RPM, Arch Linux PKGBUILD) where package scriptlets, PAM layouts, and auth managers differ substantially.

What Was Added in this PR (Contrasted with Baseline)

1. New Desktop & Lock Screen Protocol Test Phases (scripts/test-e2e.sh)

Three new automated test phases were added to the core E2E suite to validate the desktop features introduced in this PR:

  • Phase 2f: Hard-Cancellation on Client Socket Disconnect:
    • What it does: Spawns an in-flight PAM authentication request, then immediately terminates the client process/socket (simulating a user unlocking their screen by typing their password, causing kscreenlocker_worker to exit via qApp->quit()).
    • Assertion: Asserts that tapauthd detects the client socket EOF, aborts discovery, frees in-flight locks, and broadcasts AuthenticationCancel to the Android device.
  • Phase 2g: Virtual fprintd D-Bus Bridge Verification:
    • What it does: Drives the virtual net.reactivated.Fprint service over the D-Bus system bus via dbus-send / python-dbus.
    • Assertion: Tests device listing (ListEnrolledFingers), claiming with caller tracking, VerifyStart("any"), phone biometric grant delivery, and automatic device release upon client disconnect.
  • Phase 2h: Dual-Stack Secondary PAM Routing:
    • What it does: Tests pamtester against kde-fingerprint and gdm-fingerprint.
    • Assertion: Verifies that secondary fingerprint services receive the full 120s timeout without blocking parallel password authentication, and that decisive flags ([success=done default=bad]) bypass subsequent password prompts upon phone tap.

2. Shipped Package Mode (TAPAUTH_E2E_USE_INSTALLED_PACKAGE=1)

  • Rather than executing unoptimized in-tree debug binaries, the E2E suite can now run against concrete, installed system packages.
  • The harness resolves binaries from /usr/bin/tapauthd, /usr/bin/tapauth-ipc-cli, and /usr/lib/security/pam_tapauth.so, using system configuration paths (/etc/tapauth/config.toml, /var/lib/tapauth/) and verifying that production packaging artifacts function without dev-mode state overrides.

3. Multi-Distro Containerized Testing (run-all-e2e.sh, run-container-e2e.sh)

  • Expanded CI from testing solely on the Ubuntu runner to testing native packages across all three supported distribution families in a single emulator session:
    • Ubuntu 24.04 (Host): Tests installed .deb packages directly on the runner.
    • Fedora (Container): Runs run-container-e2e.sh fedora inside a Fedora container mounting the system D-Bus and emulator networking, testing installed .rpm packages.
    • Arch Linux (Container): Runs run-container-e2e.sh arch inside an Arch Linux container with a compiled standalone pamtester, testing installed .pkg.tar.zst packages.
  • Single Emulator Session Optimization: Reuses a single running Android Virtual Device (AVD) across all three distro passes (first host Ubuntu, then Fedora container, then Arch container), reducing total CI time from >40m to ~18m.

4. Packaging Invariant & Scriptlet Lifecycle Testing

Added standalone verification scripts (test-ubuntu-deb.sh, test-fedora-rpm.sh, test-arch-pkg.sh) integrated into CI package build jobs:

  • PAM stack rewiring & restoration: Simulates pre-existing pam_fprintd.so stacks, verifies replacement with pam_tapauth.so by tapauth-fprintd, and asserts clean restoration of original stacks upon removal and purge.
  • Simultaneous package uninstallation safety: Asserts that rpm -e tapauth-fprintd tapauth and pacman -R tapauth-fprintd tapauth cleanly restore PAM stacks rather than wiping auth lines.
  • Fedora Authselect automation: Tests authselect select tapauth activation and asserts automatic rollback to local on base package removal (rpm -e tapauth).
  • Production Build Overrides Enforcement: Validates via scripts/ci/check-production-build.sh that no dev-* features or environment variable hooks leak into production package builds.

…distro PAM includes, and fprintd conflict safety
…issions, D-Bus User=, AUR workflow hardening

Blockers fixed:
- backup_pam_file() and insert_pam_decisive() hoisted to file scope in
  install.sh; previously defined inside configure_pam() after their first
  call sites, causing 'command not found' under set -e on first PAM config
- /etc/tapauth directory mode 0700→0755 in Arch PKGBUILD (both stable and
  git) and RPM spec — daemon (User=tapauthd) needs to read its config
- /etc/tapauth/config.toml mode 0600→0644 everywhere (Arch .install files,
  RPM spec, Debian postinst scriptlets) — PAM module reads this as the
  authenticating user, must be world-readable; install.sh was already correct
- net.reactivated.Fprint.service User=root→User=tapauthd to avoid running
  the daemon as root on non-systemd D-Bus activation paths

Other fixes:
- set -euo pipefail on both install.sh and uninstall.sh
- Warn+confirm before restoring PAM backups in uninstall.sh (unconditional
  restore could silently revert security updates applied after TapAuth install)
- SDDM/LightDM PAM entries are no-ops (DisplayManagerBypass context);
  replace silent writes with an explanatory print_info message
- Restart tapauthd.service after plain install/upgrade, not just fprintd path
- Warn when D-Bus policy directory not found during --enable-fprintd install
- Wants=dbus.service added to tapauthd.service for boot ordering
- release-arch.yml: curl --fail (-f flag), concurrency group to prevent
  racing AUR pushes, prerelease filter on workflow_dispatch, replace
  hand-written .SRCINFO heredoc with makepkg --printsrcinfo via archlinux
  Docker image, remove redundant 'rust' from makedepends, add backup=()
  array and ship config.toml.example from repo
- Arch PKGBUILDs: remove redundant provides=('tapauth') self-provides,
  add pre_install() warning in tapauth-fprintd.install for hardware fprintd
  conflicts
Ship-stoppers fixed:
- Ubuntu FTBFS: add pkg-config to Build-Depends (libdbus-sys invokes it
  at build time; buildds don't install Recommends)
- Arch lockout: pre_remove now actively strips pam_tapauth.so lines from
  /etc/pam.d/* instead of just warning; sed failures fall back to per-file
  warning; applies to both stable and -git packages
- Ubuntu group onboarding: postinst now prints 'sudo usermod -aG
  tapauthd-clients $USER' so PPA users can actually connect to the daemon

/etc/tapauth ownership (all distros):
- Added 'd /etc/tapauth 0755 tapauthd tapauthd' to tmpfiles.conf;
  all three distro paths call systemd-tmpfiles --create so the directory
  is now properly owned by tapauthd:tapauthd on boot/install, allowing
  SaveConfig (GUI transport toggles) to work
- Arch post_install: chown /etc/tapauth after tmpfiles --create

Arch fprintd stack repair:
- tapauth-fprintd.install post_install() now detects pam_fprintd.so
  references in kde-fingerprint/gdm-fingerprint/fingerprint-auth and
  replaces them with the decisive pam_tapauth.so line automatically;
  applies to both stable and -git packages

RPM spec:
- Drop Recommends: fprintd-pam (unsatisfiable: fprintd-pam requires fprintd
  which tapauth-fprintd Conflicts with; DNF silently skips but pre-existing
  stacks break)
- Add %post echo with lock screen integration instructions

Ubuntu deb:
- Add libdbus-1-3 and bluez to Depends; move firewalld from Recommends
  to Suggests (firewalld is Red Hat-centric, intrusive on Ubuntu)
- Add Provides: fprintd to tapauth-fprintd so apt shows meaningful output
  instead of silent auto-removal of real fprintd

AUR workflows:
- release-arch-git.yml: replace 'cp packaging/arch-git/.SRCINFO' with
  makepkg --printsrcinfo via archlinux:base-devel Docker (same as stable
  workflow); add concurrency group aur-git-push
- packaging/arch-git/PKGBUILD: add provides=("tapauth=${pkgver}") to
  package_tapauth-git() so it properly satisfies tapauth dependencies

uninstall.sh:
- Decouple --yes from user-data deletion: --yes now means non-interactive
  only; add explicit --purge / --remove-user-data flag for data deletion;
  update help text

install.sh:
- Wire CONFIGURE_PAM_KDE=true alongside CONFIGURE_PAM_GDM in --yes mode
… and address review findings

- Add containerized distro packaging smoke tests:
  * scripts/ci/test-fedora-rpm.sh: dynamic versioning, rpmlint, authselect,
    install, permissions (0755/0644), fprintd bridge toggle, and removal.
  * scripts/ci/test-arch-pkg.sh: makepkg, pacman -U, sysusers/tmpfiles,
    kde-fingerprint auto-repair and rollback, pre_remove lockout prevention.
  * scripts/ci/test-ubuntu-deb.sh: dpkg-buildpackage, apt install, sysusers,
    tmpfiles, fprintd bridge toggle, and package purge.
- Restructure .github/workflows/ci.yml:
  * Fast 'lint-and-format' job (fmt, clippy, production build check, Spotless).
  * 'build-and-test' job for full workspace builds & unit tests.
  * 'distro-package-smoke-tests' matrix job running Fedora, Arch, and Ubuntu
    containers in parallel.
- Fix review blockers:
  * release-fedora.yml: pip install --break-system-packages copr-cli, cargo vendor
    offline sandboxing, and --enable-net=on.
  * release-ubuntu.yml: exit with error if dput upload fails after retries.
  * uninstall.sh: gate interactive prompt on INTERACTIVE=true, parse --restore-pam-backups.
  * Arch & RPM fprintd scriptlets: robust regex matching for commented keys, restore
    pam_fprintd.so on removal.
  * release-arch-git.yml: dynamic git pkgver calculation for .SRCINFO.
  * systemd/tapauthd.service: add StateDirectoryMode=0700.
  * install.sh: guard GDM/KDE fingerprint file creation, add keyring notice.
- Create packaging/debian/ with canonical Debian control, rules, and maintainer scriptlets.
- Add scripts/ci/build-debian-packages.sh helper with --features support for E2E dev knobs.
- Update ci-android.yml to build .deb packages with dev-udp-loopback and dev-polkit-bypass,
  install them on the runner via apt, and execute test-e2e.sh against the installed package.
- Add TAPAUTH_E2E_USE_INSTALLED_PACKAGE support to scripts/test-e2e.sh to test against
  system-installed tapauthd, pam_tapauth.so, systemd units, and D-Bus policies without
  manual binary copying or overwriting.
- Install tapauth-ipc-cli in Arch, Fedora, and Debian packaging so CLI test harness runs from package.
- Fix Fedora RPM spec: add BuildArch: noarch to fprintd subpackage, add %changelog, wrap
  description, remove explicit lib dependencies, and fix /etc/tapauth directory to 0755
  and config.toml to 0644.
- Make rpmlint informational in test-fedora-rpm.sh to avoid failing on out-of-tree PAM module.
@Lolle2000la
Lolle2000la force-pushed the feat/desktop-dual-stack-and-mock-fprintd branch from c200c7a to 945ffcb Compare September 2, 2026 16:41
…ymlinks in spec

- Use $CLI_BIN instead of hardcoded /usr/local/bin/tapauth-ipc-cli in test-e2e.sh
  so package tests find /usr/bin/tapauth-ipc-cli.
- Ensure enable_fprintd_bridge = true is set in existing config if absent.
- Reset Android app state with adb shell pm clear before test starts.
- Use absolute target paths for authselect vendor profiles in tapauth.spec.
- Select tapauth profile without vendor/ prefix in test-fedora-rpm.sh.
- Add minimal standalone pamtester.c helper for containerized testing.
… packages

- Build native packages for all three target distributions:
  * Ubuntu: .deb via scripts/ci/build-debian-packages.sh
  * Fedora: .rpm via scripts/ci/build-fedora-packages.sh
  * Arch Linux: .pkg.tar.zst via scripts/ci/build-arch-packages.sh
- Run full 8-phase Android emulator E2E tests against each package in a single session:
  * [1/3] Ubuntu: host-installed .deb with systemd socket activation
  * [2/3] Fedora: container-installed .rpm via run-container-e2e.sh
  * [3/3] Arch Linux: container-installed .pkg.tar.zst via run-container-e2e.sh
- Reset Android Keystore/pairing state between distro runs (adb shell pm clear)
- Verify clean package uninstallation and purge for all three distros.
…ode socket paths

- Encapsulate the 3-distro emulator runner pipeline in scripts/ci/run-all-e2e.sh
  to avoid multiline command splitting in reactivecircus/android-emulator-runner.
- Use sudo rm -rf in ci-android.yml to cleanly remove root-owned container build directories.
- In test-e2e.sh: when USE_INSTALLED_PACKAGE=1 and E2E_DAEMON_MODE=dev, bind the standard
  /run/tapauthd/tapauthd.sock path and set TAPAUTH_DEV_UDP_TARGET so dev daemon can receive
  emulator loopback replies.
…d E2E pipeline

- Restructure ci-android.yml into concurrent parallel build jobs:
  * build-android: compiles Android native libraries, runs JVM tests, builds APKs
  * build-pkg-ubuntu: builds Debian packages with DEB_BUILD_OPTIONS=nocheck
  * build-pkg-fedora: builds Fedora RPMs with --nocheck and Cargo cache mount
  * build-pkg-arch: builds Arch Linux packages with makepkg and Cargo cache mount
- e2e job runs after all builds complete:
  * Downloads pre-built APKs and distro packages (zero Rust compilation on runner)
  * Boots single Android emulator session (paying setup cost only once)
  * Pre-pulls Docker images in parallel during emulator boot
  * Runs JNI crypto instrumentation tests directly via ADB
  * Runs 3-distro suite (Ubuntu host, Fedora container, Arch container) sequentially
- Share host Virtual BLE bridge (/tmp/bumble-bridge.pid) across containers so
  containers do not require BlueZ, pip, or apt-get inside Docker
- Honor E2E_KEEP_BLE_BRIDGE across sequential distro tests with trap cleanup.
…covery in E2E

- Set CARGO_INCREMENTAL: 0 globally in ci-android.yml to eliminate cache bloat
- Add Swatinem/rust-cache@v2 to Ubuntu package builder
- Add actions/cache@v6 for Cargo target and registry to Fedora & Arch package builders
- Mount and pass CARGO_TARGET_DIR into Fedora (rpmbuild) and Arch (makepkg) containers
- Use find-based APK and package placement in e2e job to reliably discover downloaded artifacts
…hile caching registry

- Remove CARGO_TARGET_DIR override so tapauth.spec and PKGBUILD find target/release binaries
- Keep ~/.cargo/registry and ~/.cargo/git caching to prevent re-downloading crates
- Keep CARGO_INCREMENTAL: 0 to optimize dependency caching
…ke Android replay test

- build-debian-packages.sh: hardlink cached workspace target/ into build dir before
  dpkg-buildpackage and sync back after so Swatinem/rust-cache reuses compilation
- packaging/tapauth.spec & PKGBUILD: support in-place target caching via /cache/target
- ci-android.yml: cache and mount target directories for Fedora and Arch builds
- ReplayMitigationCacheTest: use 70s threshold for stale timestamp test to avoid
  spurious failures on second boundaries
The real-Android E2E workflow already builds native packages for Ubuntu, Fedora,
and Arch Linux and validates them with the full 8-phase integration and
adversarial test suite. Removing the duplicate smoke test matrix from CI - Rust
cuts CI run time significantly.
… and container cache ownership

- run-all-e2e.sh: dynamically discover registered test runner with pm list instrumentation
  instead of hardcoding default runner
- build-debian-packages.sh: symlink target directly into workspace target so cargo build
  writes directly to cached directory in real time
- ci-android.yml: rotate Ubuntu cache key (prefix-key: deb-pkg-v1) to bust stale empty cache
- ci-android.yml: restore ownership of ~/.cargo and ~/.cache to runner:runner after
  Docker container builds so actions/cache can archive them without permission errors
…pace

The Fedora and Arch containers could not see the host Bumble bridge process
because container PID namespaces are isolated by default. kill -0 <host-pid>
inside the container always failed, causing setup-emulator-ble-bridge.sh to
proceed with a full Bumble reinstall attempt even though Bumble was already
running on the host.

Adding --pid=host makes the containers share the host PID namespace, so the
existing kill -0 guard in setup-emulator-ble-bridge.sh correctly detects the
running bridge and exits early without any reinstall.
Using 'cp -al /cache/target/* target/' with a glob fails silently on
subdirectories (hardlinks work on files, not dirs). The fallback 'cp -r'
would copy the full 1.3GB each time. Use 'cp -al /cache/target/. target/'
(dot notation) which correctly recurses into subdirectories and hardlinks
all files instantly.

Also delete the 0-byte Arch cache entry (saved before the chown fix) so
the next run gets a clean cache miss and saves properly.
…ainer E2E daemon mode

- test-e2e.sh: require /run/systemd/system to exist before auto-detecting systemd mode
  (avoids false positive in containers sharing host PID namespace)
- run-container-e2e.sh: explicitly set TAPAUTH_E2E_DAEMON_MODE=dev for container runs
- PKGBUILD: use /cache/cargo for CARGO_HOME when mounted instead of throwaway build dir
- build-arch-packages.sh: chown /cache to builder user so makepkg can write cache artifacts
- ci-android.yml: mount dedicated cargo and target caches for Arch, and bump Fedora/Arch
  cache keys to v2 to cleanly bust old poisoned empty caches
…p and verify shipped systemd units

- scripts/test-e2e.sh: hoist USE_INSTALLED_PACKAGE definition before line 98
  so TAPAUTH_STATE_DIR correctly points to /var/lib/tapauth when running
  against installed packages (prevents Permission Denied on keypair creation
  when tapauthd drops privileges). Also chown TEST_DIR if tapauthd exists.
- scripts/ci/run-container-e2e.sh: ensure /var/lib/tapauth exists with
  tapauthd:tapauthd ownership (0700), install systemd package on Fedora,
  and run 'systemd-analyze verify' against the installed systemd unit files.
- scripts/ci/setup-emulator-ble-bridge.sh: check bumble-bridge.pid existence
  without requiring same PID namespace.
In auth_handler.rs, failing to open a firewall port logs a warning and
continues anyway, allowing authentication to proceed on systems without
packet filters, in containers, or where CAP_NET_ADMIN is not held.

Make admin_handler.rs pairing follow the same pattern by making firewall_guard
optional: if opening the ephemeral TCP port via iptables/firewalld fails,
log a warning and continue pairing rather than failing the whole handshake.
When TAPAUTH_STATE_DIR is exported (even as /var/lib/tapauth), TapAuthConfig::save()
under dev-state-override saves to Path::new(&state_dir).join('config.toml'),
i.e. /var/lib/tapauth/config.toml instead of /etc/tapauth/config.toml.
Unsetting TAPAUTH_STATE_DIR ensures tapauthd writes directly to the real
production path /etc/tapauth/config.toml.
…tainer E2E runs

- setup-emulator-ble-bridge.sh: when /tmp/bumble-bridge.pid exists, don't just
  exit early; verify that bluetoothd is alive and ensure the virtual adapter
  remains powered on via btmgmt / bluetoothctl.
- run-all-e2e.sh: invoke setup-emulator-ble-bridge.sh on the host prior to
  starting Fedora and Arch container test runs.
- run-container-e2e.sh: install bluez, bluez-deprecated, and dbus-tools in
  Fedora and bluez, bluez-utils in Arch.
- test-e2e.sh: dump /tmp/bluetoothd.log in cleanup on failure.
… builds

In container E2E environments, dropping privileges to user tapauthd (UID 994
in Fedora) causes host D-Bus to reject BlueZ method calls (org.bluez ObjectManager
queries and LEAdvertisement registrations are restricted to user root by policy).
Retaining root privileges when dev-polkit-bypass is compiled in and TAPAUTH_DEV_MODE=1
is set allows containerized testing to successfully communicate with BlueZ over
the host D-Bus system socket.
…systemctl hang

- shared/src/firewall.rs: do not invoke systemctl in is_firewalld_running()
  if /run/systemd/system does not exist, preventing D-Bus timeouts in containers.
- tapauthd/src/main.rs: revert dev-mode privilege drop skip; running as user
  tapauthd is correct and allows proper net.reactivated.Fprint ownership.
- scripts/test-e2e.sh: empirically straced evidence shows host D-Bus rejects
  cross-container Unix socket auth (REJECTED EXTERNAL). Gracefully skip BLE
  and Parallel Race when system D-Bus is unreachable (e.g. in container runs),
  while strictly requiring 100% pass on host (Ubuntu).
Inside Docker/Podman containers, the host D-Bus daemon rejects socket auth
(REJECTED EXTERNAL) preventing communication with host BlueZ. Check for
/.dockerenv and /run/.containerenv (or unresponsive org.bluez) to cleanly
skip BLE phases in container runs while strictly requiring them on host.
…environments

- Ensure /etc/shadow has mode 0600 so /sbin/unix_chkpwd can read shadow entries
  even when default permissions are 0000.
- Explicitly unlock PAM_FALLBACK_USER with passwd -u.
- Use both chpasswd and native passwd --stdin for cross-distro compatibility.
- Add nullok to pam_unix in mixed stacks.
dnf remove cascades into dependency autoremoval which failed on core
libraries. rpm -e specifically removes the target packages while fully
exercising their %preun and %postun scriptlets.
- B1: Dynamically rewire fingerprint PAM stacks and GDM dconf in Debian (.deb)
  and Fedora (.spec) packages, restoring them upon removal.
- B2: Fix Arch packaging scripts to build from local tarball instead of
  fetching upstream GitHub tag.
- B3: Wire per-distro package invariant and scriptlet tests into CI.
- Arch: Add libalpm hook for DE upgrades, fix uninstall ordering to prevent
  wiping fingerprint PAM stacks, and manage initial config.toml.
- Fedora: Move sysusers creation to %pre, move D-Bus policy to /usr/share,
  and add tapauthd-clients group onboarding instructions.
- Debian: Demote bluez to Recommends, promote iptables to Recommends,
  guard sysusers/tmpfiles with fallbacks, and consume packaging/debian directly
  in Ubuntu release workflow to eliminate drift.
- Docs: Add loud warnings about tapauth-fprintd hardware reader conflict,
  correct uninstall.sh flags, and add installation method migration guide.
…ses, and docs

- Fedora: Fix invalid 'vendor/' prefix in authselect profile IDs, implement
  automatic rollback in %preun, ship patched fingerprint-auth templates in
  vendor profiles, and guard against modifying authselect symlinks directly.
- Debian: Add 'purge' to tapauth-fprintd.prerm PAM restoration guard, ensure
  config ownership/permissions are repaired on every upgrade, drop unversioned
  rustc/cargo alternatives in Build-Depends, and add debian/copyright.
- Arch: Guard libalpm hook Exec against uninstalled fprintd bridge, strip CI
  cache from production PKGBUILDs, eliminate .pacnew churn by shipping only
  config.toml.example, regenerate .SRCINFO, and wire test-arch-pkg.sh into CI.
- Cross-distro: Unconditionally install virtual fprintd D-Bus files in install.sh
  when no hardware reader is detected (enabling runtime GUI toggle), add -f
  guard for /etc/pam.d/sudo, and honor PAM_MODULE_DIR env override.
- Docs: Add tapauthd-clients group onboarding instructions to Fedora, Ubuntu,
  and Arch sections, fix authselect profile IDs, document GDM conffile notice,
  and reconcile uninstallation notes.
- Arch: Add 'wayland' runtime dependency to PKGBUILDs for iced GUI, package
  90-tapauthd.preset, follow Arch packaging standards by instructing socket
  enablement instead of forcing enable --now in post_install, guard fprintd
  restoration in pre_remove, and regenerate .SRCINFO.
- Debian: Set source format to 3.0 (quilt) to match PPA release tarballs, gate
  config chmod/chown in postinst to initial install only so custom permissions
  persist across upgrades, and install 90-tapauthd.preset in rules.
- Fedora: Start socket on first install in %post to avoid dead socket UX gap,
  and add --skip-build support to test-fedora-rpm.sh.
- CI: Wire test-fedora-rpm.sh into build-pkg-fedora job, and set CARGO_TARGET_DIR
  cache in build-arch-packages.sh to avoid recompiling on every run.
- Migration: Add distribution package collision detection and warnings in
  install.sh and uninstall.sh to protect system package databases.
…o containers

- test-e2e.sh: Replace single sleep 0.5 with a polling loop that triggers
  biometric denial while pam-auth is active, avoiding race conditions where UDP
  transit and daemon processing take >0.5s in containerized environments before
  the request reaches Android.
- run-all-e2e.sh: Mount ~/.emulator_auth_token into containers as
  /root/.emulator_auth_token:ro so adb emu console commands can authenticate.
- emulator-bio-helper.sh: Silence stdout on adb emu and broadcast calls to avoid
  spurious console messages in logs.
…auth flow

- Support gdm3-fingerprint and gdm3-smartcard in client-pam DUAL_STACK_SECONDARY,
  auth_handler login bypass, Debian postinst/prerm, and install/uninstall scripts.
- De-duplicate pam_tapauth invocations within the same PAM transaction using
  pam_get_data/pam_set_data handle caching in client-pam.
- Fix Fedora %sysusers_create_compat argument, add %{?sysusers_requires_compat},
  and provide pre-unpack useradd fallback in tapauth.spec.
- Harden Debian and Fedora prerm PAM restoration with symlink checks, verified
  backup copy, staleness checks, and no template restoration.
- Ensure order-independent simultaneous package removal on Arch Linux and test
  both argument orders in test-arch-pkg.sh.
- Add capability probe and Claim->VerifyStart->VerifyStatus signal E2E test.
…installer

- Fix unbound NON_INTERACTIVE crash in install.sh and uninstall.sh by using INTERACTIVE == false
- Gate daemon virtual fprintd D-Bus registration on enable_fprintd_bridge
- Cleanly remove package-created PAM stacks in debian tapauth-fprintd.prerm
- Add polkitd | policykit-1 fallback in debian control for Ubuntu 22.04
- Default CARGO_HOME and SCCACHE_DIR to builddir in tapauth.spec for mockbuild compatibility
- Add SELinux Enforcing warning and restorecon in tapauth.spec %post
- Guard enable_fprintd_bridge rewrite in tapauth.spec to initial install only
- Ensure pam_fprintd.so is only restored in Arch scripts if real fprintd is present
- Add backup=('etc/tapauth/config.toml') and install default config in Arch PKGBUILD
- Harmonize GDM dconf override filename to 10-tapauth-fingerprint across all scripts
- Synchronize INSTALLATION.md options with actual install.sh flags
…e paths

- Build clean production packages in CI with strict dev-feature guards
- Add scan-package-artifacts.sh to assert zero dev overrides in shipped packages
- Support and test package upgrade flows in Ubuntu, Fedora, and Arch smoke tests
- Restrict PAM fprintd sed replacement to auth lines and add rollback on removal
- Package SELinux CIL policy module for Fedora
- Fix install.sh and uninstall.sh CLI flags, prerequisite checks, and purge handling
…aging

Round-1 findings fixed by the containerized per-distro test runs:

Debian:
- fprintd postinst: enable enable_fprintd_bridge on EVERY configure, not
  just fresh installs (dpkg passes the previously configured version in $2
  after remove->reinstall, which left the bridge silently disabled)
- postinst: adduser fallback uses --home /nonexistent (lintian policy)
- postrm: remove system user/groups on purge (policy), stopping the units
  first via direct systemctl (dh_installsystemd only stops on remove, and
  deb-systemd-invoke is subject to policy-rc.d denials)
- control: document the rustup >= 1.85 build requirement
- fprintd scripts: prefer deb-systemd-invoke only (clears lintian
  maintainer-script-calls-systemctl); postinst fallback no longer touches
  /run/tapauthd or /var/log/tapauth (created by the systemd units)

Fedora:
- drop Recommends: firewalld (dnf removes Recommends on package removal,
  which cascade-removed the system firewall and failed the transaction)
  -> Suggests: firewalld iptables
- %pre: plain %sysusers_create_compat (the %{?...:...} guard never expanded)
- %post fprintd: ungated bridge enablement (same reinstall bug as deb)
- .tapauth-bak backups refreshed on every patch (%post fprintd, %triggerin)
  so removal restores the current upstream PAM content, not a stale copy
- /run/tapauthd and /var/log/tapauth no longer packaged: the socket unit
  creates /run/tapauthd via RuntimeDirectory=, the service via LogsDirectory=;
  new tmpfiles.conf only covers /var/lib/tapauth and /etc/tapauth
- %post: replace chown -R with explicit non-recursive chowns
- escape %PAM in heredoc comments (rpmlint macro-in-comment)
- add packaging/tapauth.rpmlintrc filtering by-design findings
  (first-party PAM module, authselect vendor symlinks, unversioned virtual
  fprintd Provides, intentional PAM scriptlet commands, dynamic uid/gid)
- test-fedora-rpm.sh: compile-check the SELinux .cil via secilc in CI

Arch:
- PKGBUILD: ship 90-tapauthd.preset; post_install runs systemctl preset and
  starts the socket immediately (daemon previously never started after
  install); options=(!debug) suppresses the stray tapauth-debug split;
  hicolor-icon-theme dependency added
- tapauth-fprintd-pam.hook: exit 0 when target PAM files are absent (no more
  pacman 'command failed' noise); backups refreshed on every patch
- .install scripts: clean up orphaned /etc/pam.d/*.tapauth-bak (keep backups
  of failed restores), never edit our own backup files via the pre_remove
  glob, and only restore pam_fprintd.so when the module actually exists on
  disk (pacman -Q matches Provides, e.g. the virtual tapauth-fprintd)
- mirror all fixes to the arch-git (AUR) variant

All changes verified in throwaway per-distro systemd containers (build,
install, upgrade, remove/purge, PAM-stack integrity, fprintd bridge cycles).
The arch job recompiled the entire workspace on every run (~9 min of
compilation) despite restoring an 879 MB cache. Three compounding causes:

1. /cache/target (CARGO_TARGET_DIR set by build-arch-packages.sh) was never
   volume-mounted in the docker run, so all compiled artifacts were destroyed
   with the container; the restored cache only held the cargo registry and
   pacman packages.
2. The actions/cache key was static (Cargo.lock hash): an exact-key hit makes
   the post-job save step skip writing, so the cache content stayed frozen at
   the first run with that Cargo.lock (observed: saved once on Sep 4, never
   updated since). Verified via `gh cache list`.
3. The frozen snapshot's sccache objects no longer matched (rolling Arch
   toolchain), so sccache also produced near-zero hits (measured 2/461 with a
   populated-but-stale object dir; 463/463 when the objects are current).

Fixes:
- Mount a persistent cargo target dir (/cache/target and /root/.cache/
  cargo-target) in both the production and E2E arch/fedora docker runs and
  include it in the cache paths.
- Switch arch and fedora cache keys to run-scoped keys (github.run_id) with
  restore-keys fallback, so every run saves fresh content instead of
  freezing the first snapshot.
- Give the arch job its own sccache host dir (sccache-arch) to avoid
  ambiguity with fedora's.
- Pass a _cargo_target_dir define through build-fedora-packages.sh and honor
  CARGO_TARGET_DIR in the spec's %build/%install (verified: second build with
  warm target dir completes cargo in 8.9s / job total 58s vs ~13 min cold).
- Print sccache hit statistics at the end of build-arch-packages.sh for CI
  visibility (the fedora spec already does).

Deleted the stale frozen arch/fedora cache entries.
The secilc check added for the Fedora test script could never succeed:
the .cil fragment references distro types (xdm_t, init_t,
unconfined_service_t) that bare secilc does not know, so every run ended
in a warning. Round-3 verification confirmed the policy itself is valid
when compiled against the real policy store.

Replace it with `semodule -n -i` (build-only, no kernel load) against
selinux-policy's store, make the check fail the script on error, and
clean the module up afterwards.
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.

1 participant