Last updated: 2026-07-07
Build state: v0.3.6 shipped. All 6 implementation steps complete + model integrity enforcement + OSS governance + passive liveness detection. Since v0.3.3: fixed capture degradation on shared webcams (per-capture V4L2 format re-assert + in-process camera self-heal, #48); the IR emitter quirks DB now covers ASUS Zenbook 14 UM3406HA, Lenovo ThinkPad X1 Carbon Gen 9, Lenovo ThinkBook 14 MP2PQAZG, and HP OmniBook X Flip; NixOS flake build fixed; Dependabot security updates + a scheduled cargo audit enabled; contribution review reframed problem-first (ADR 010 §9). v0.3.6 added a security hardening batch: in-process root checks on the privileged D-Bus methods (Enroll/RemoveModel/ListModels), the VISAGE_SESSION_BUS flag and passive liveness now fail closed, zbus pinned to the tokio executor (drops the async-io stack), and an AES-256-GCM known-answer + blob-format test. End-to-end tested on Ubuntu 24.04.4 LTS. Passive liveness still awaits manual spoof testing on hardware.
| Step | Component | Status |
|---|---|---|
| 1 | Camera pipeline (visage-hw) |
✅ Complete — V4L2, GREY/YUYV/Y16, CLAHE, dark frame filter |
| 2 | ONNX inference (visage-core) |
✅ Complete — SCRFD detection, ArcFace recognition, face alignment |
| 3 | Daemon + D-Bus + SQLite (visaged) |
✅ Complete — persistent daemon, 5-method API, WAL store |
| 4 | PAM module (pam-visage) |
✅ Complete — PAM_IGNORE fallback, system bus, FFI safe |
| 5 | IR emitter (visage-hw) |
✅ Complete — UVC extension unit, quirks DB (ASUS Zenbook 14, Lenovo X1 Carbon Gen 9) |
| 6 | Packaging | ✅ Complete — .deb, systemd, pam-auth-update, visage setup |
| 7 | Model integrity (visage-models) |
✅ Complete — pinned SHA-256, fail-closed daemon startup, shared manifest |
| 8 | Passive liveness (visage-core, visaged) |
cargo check/test + hardware spoof validation |
Tested on Ubuntu 24.04.4 LTS (CCX20, USB webcam /dev/video2, GREY format, CPU-only ONNX). Items marked ✅ have been verified; items marked ⬜ require hardware not available on the test machine.
-
visage enroll --label default— captures 5 frames, confidence-weighted averaging, stores encrypted model, returns UUID -
visage verify— matches enrolled face, exits 0 (similarity 0.97 with v0.3.0 enrollment; 0.83 with legacy plaintext enrollment) -
visage verify— returns exit 1 on no-match (different person or covered camera) — requires interactive test -
visage verifycompletes in <500ms (warm daemon, good IR illumination) — 1.4s on USB webcam/CPU; needs IR+GPU test - 10 consecutive
sudo echo testattempts: ≥9 succeed via face recognition — requires interactive test
- Cover camera →
sudofalls back to password within 3 seconds (PAM timeout) — requires interactive test - Kill visaged →
sudofalls back to password within 3 seconds - Restart daemon → re-enroll not required (data persists in SQLite)
- No output in terminal on PAM failure — only in
/var/log/auth.log
-
sudo apt install ./visage_*.debon Ubuntu 24.04 succeeds (upgrade v0.1.0 → v0.3.0 verified) -
systemctl status visagedshows active after setup (note:systemctl restart visagedrequired after package upgrade) -
grep visage /etc/pam.d/common-authshows pam_visage.so entry -
sudo visage setupdownloads and verifies both ONNX models (182 MB, SHA-256) -
sudo apt remove visage→grep visage /etc/pam.d/common-authshows no entry - Password-based
sudoworks correctly after remove -
sudo apt purge visageremoves/var/lib/visage/directory
-
systemctl show visaged --property=ProtectSystemreturnsstrict -
systemctl show visaged --property=NoNewPrivilegesreturnsyes -
systemctl show visaged --property=DeviceAllowreturnschar-video4linux rw
-
visage enrollas non-root user is rejected (D-Bus policy) -
visage listas non-root user is rejected (D-Bus policy) -
visage removecross-user is rejected (store-level protection) -
visage verifyas non-root user succeeds (D-Bus policy allows) -
visage statusas non-root user succeeds
- Package upgrade v0.1.0 → v0.3.0 via
apt installsucceeds cleanly - Legacy plaintext enrollment readable after upgrade (transparent migration path)
- New encryption key generated on first v0.3.0 daemon start (old key absent)
- Model integrity check passes at daemon startup (silent success)
-
visage statusshows new fields:model_dir,timeout,verify_n,enroll_n,emitter,bus -
visage discovershows kernel driver per device, VID:PID, quirk status - Re-enrollment with v0.3.0 produces encrypted embedding (AES-256-GCM)
- PAM face auth works after re-enrollment (
sudo -k && sudo echo test— similarity 0.91)
- IR emitter activates at daemon start (no manual intervention after reboot) — daemon starts via systemd on boot
- Suspend → resume →
sudo echo testworks (daemon restarted via systemd sleep hook)
-
DeviceAllow=/dev/video* rw(commit 51b5eff) — glob pattern doesn't work in systemd's cgroup v2 device policy. Even root is blocked. Fixed tochar-video4linux rw(kernel device type). -
tokio::time::timeoutpanic (commit 51b5eff) — zbus dispatches D-Bus method handlers on its own async executor, not Tokio's.tokio::time::timeoutpanics without Tokio reactor. Fixed by moving timeout enforcement into the engine thread viastd::time::Instantdeadline.
-
End-to-end install test on Ubuntu 24.04— DONE (2026-02-22, CCX20) -
GitHub Actions CI pipeline— DONE (2026-02-22,.github/workflows/ci.yml)- fmt, clippy, build, test, cargo-deb, GitHub Release on
release:commit prefix
- fmt, clippy, build, test, cargo-deb, GitHub Release on
-
IR emitter suspend/resume hook— DONE (systemd sleep hook restarts visaged on resume) -
ONNX model integrity verification— DONE (v0.3.0, commit 5d001c2)visage-modelscrate: pinned SHA-256, shared manifest,verify_models_dirvisagedfails closed at startup if models are missing or checksums mismatchvisage setuprefactored to use shared manifest (no duplicated model list)- ADR 009 documents rationale, trade-offs, and known limitations
-
OSS contribution governance— DONE (2026-02-24)SECURITY.md: private vulnerability reporting via GitHub Security Advisories- Branch protection on
main: required PR, 1 approval,teststatus check, no force push CODEOWNERS:@sovren-softwareowns all paths; explicit entries for security crates- Issue templates: bug report, hardware report, feature request + config.yml
- PR template: type, description, testing, quality gate checklist
CONTRIBUTING.md: DCO sign-off policy, merge strategy, review timeline- Dependabot: weekly Cargo + GitHub Actions dependency PRs
- LICENSE copyright corrected to Sovren Software
- ADR 010 documents rationale, trade-offs, and known limitations
-
Rate limiting— DONE — 5 failures/60s sliding window → 5-min lockout -
Hardware compatibility docs and IPU6 detection— DONE (commit 7d0f9e1)visage discovernow shows kernel driver per device; warns on IPU6 with explanationdocs/hardware-compatibility.mdcreated with tier table, laptop examples, emitter process- README hardware section rewritten with UVC/IPU6 tier table
- ADR 008 documents decision rationale and trade-offs
-
NixOS packaging — Augmentum OS overlay integration; Tier 1 in distribution strategy
- Path:
packaging/nix/(derivation present) - Blocked on: flake wiring / nixpkgs submission decisions
- Path:
-
GitHub release with pre-built
.deb— necessary for users without Rust toolchain -
Debian changelog — required for Launchpad PPA submission; not present
- Launchpad PPA for
sudo apt install visage(no source build required) - AUR package for Arch Linux
- COPR for Fedora (timing: Fedora 43 dlib removal window)
- In-method D-Bus UID validation via
GetConnectionCredentials - Dedicated service user with udev rules (replaces root+DeviceAllow)
systemd-tmpfiles.dentry for/var/lib/visage(replaces postinst mkdir)- Active liveness detection (blink challenge — complements passive liveness, ADR 011)
| Limitation | Impact | Mitigation | ADR |
|---|---|---|---|
| Resolved — 5 failures/60 s → 5 min lockout; engine errors excluded | -- | ||
user param not validated |
Resolved — caller UID verified via GetConnectionUnixUser; root exempt; session bus skips (dev mode) | ADR 007 | |
Resolved — AES-256-GCM at rest; per-installation key at {db_dir}/.key (mode 0600) |
ADR 003 | ||
| Partially resolved — passive landmark stability blocks static photos; video replay still possible | ADR 011 | ||
| No active liveness | Video replay of enrolled user passes passive check | Active blink/head-turn challenge required — deferred to v0.4 | ADR 011 |
MemoryDenyWriteExecute=false |
Daemon can map W+X pages | Architectural: ONNX Runtime requires JIT; all other sandbox directives apply | ADR 007 |
| Ubuntu only | No other distributions | .deb ships; NixOS, AUR, COPR pending | ADR 007 |
| ~1.4s verify latency | Above 500ms target | Hardware-dependent: CPU-only ONNX on USB webcam; target <500 ms requires IR camera + hardware acceleration | -- |
| Crate | Tests | What they cover |
|---|---|---|
pam-visage |
5 | PAM/syslog constant values, D-Bus error handling without daemon |
visage-core |
38 | Detection, alignment, recognition preprocessing, matching, liveness landmark stability |
visage-hw |
9 | Frame processing, CLAHE, dark frame detection, pixel conversion |
visage-models |
4 | SHA-256 verification: missing file, checksum mismatch, checksum match, missing directory |
visaged |
14 | Rate limiting, store roundtrip, encryption, corruption hardening |
| Total | 70 | Unit tests — no integration tests; no hardware tests |
Integration tests (camera + inference + daemon + PAM) are not present. They require physical hardware (IR camera) and are deferred to manual acceptance testing on Ubuntu 24.04.