// Contract tests for client install-time security defaults. // // Scope: inspect the client installer shell contract without running it. // Targets: `scripts/install/client.sh`. // Why: secure-by-default relay transport depends on installing the server-issued // client cert bundle exactly where the desktop app auto-discovers it. const CLIENT_INSTALL: &str = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), "/scripts/install/client.sh" )); #[test] fn client_install_accepts_server_generated_tls_bundle() { for expected in [ "LESAVKA_CLIENT_PKI_BUNDLE", "CLIENT_PKI_DIR", "ca.crt", "client.crt", "client.key", "install_client_pki_bundle", "fetch_client_pki_bundle", "LESAVKA_CLIENT_PKI_SSH_SOURCE", "LESAVKA_CLIENT_CAPTURE_DIR", "theia:/etc/lesavka/lesavka-client-pki.tar.gz", "Pictures/lesavka", "HTTPS/mTLS relay connections will not work until this bundle is installed", "TLS identity:", "Captures:", "$USER_HOME/.local/bin/lesavka-client", "User PATH alias:", ] { assert!( CLIENT_INSTALL.contains(expected), "client installer should include TLS bundle contract fragment {expected}" ); } assert!( CLIENT_INSTALL.contains(".config/lesavka/pki"), "client cert bundle should land in the same path the desktop app auto-loads" ); assert!( CLIENT_INSTALL.contains("0600"), "client private key should be installed with private permissions" ); assert!( CLIENT_INSTALL.contains("scp -q -o BatchMode=yes"), "client installer should auto-fetch the server enrollment bundle without hanging" ); assert!( CLIENT_INSTALL.contains("run_as_user mktemp"), "auto-fetch destination should be owned by the user who runs scp" ); } #[test] fn client_install_prefers_invoked_checkout_for_development_installs() { for expected in [ "INSTALL_SOURCE=${LESAVKA_INSTALL_SOURCE:-auto}", "resolve_source_checkout", "Using local source checkout", "set LESAVKA_INSTALL_SOURCE=ref", "LESAVKA_INSTALL_SOURCE=local requested", "unsupported LESAVKA_INSTALL_SOURCE", "source_revision", "+dirty", ] { assert!( CLIENT_INSTALL.contains(expected), "client installer should preserve local-source install marker {expected}" ); } assert!( CLIENT_INSTALL.find("resolve_source_checkout").unwrap() < CLIENT_INSTALL .find("cargo clean && cargo build --release") .unwrap(), "client installer should resolve source before building" ); } #[test] fn client_install_reports_nvidia_and_open_source_media_routes() { for expected in [ "report_client_media_acceleration", "gst_element_available", "first_available_gst_element", "nvidia-smi is available", "proprietary NVIDIA GStreamer route", "open-source VAAPI/V4L2 GStreamer route", "nvh265enc", "nvh264dec", "nvh264sldec", "vah265enc", "vaapih265enc", "v4l2h265enc", "vah264dec", "vaapih264dec", "v4l2h264dec", "v4l2slh264dec", "x265enc", "avdec_h264", "openh264dec", "opusenc", "opusdec", "Opus upstream audio transport route", "microphone noise suppression route", "webrtcdsp", "fall back to PCM", "LESAVKA_H264_DECODER_PREFERENCE=software", ] { assert!( CLIENT_INSTALL.contains(expected), "client installer should preserve media acceleration fragment {expected}" ); } assert!( CLIENT_INSTALL .find("require_gst_element pipewiresrc") .unwrap() < CLIENT_INSTALL .rfind("report_client_media_acceleration") .unwrap(), "media acceleration reporting should run after baseline GStreamer tools are verified" ); } #[test] fn client_install_treats_pipewire_as_one_coherent_transaction() { for expected in [ "pacman_install()", "libpipewire pipewire pipewire-audio pipewire-alsa pipewire-jack pipewire-pulse", "breaks dependency '.*pipewire", "PipeWire packages are at mixed exact versions", "sudo pacman -Syu", "failed retrieving file", "sudo pacman -Syu --disable-download-timeout", ] { assert!( CLIENT_INSTALL.contains(expected), "client installer should preserve PipeWire transaction marker {expected}" ); } assert!( !CLIENT_INSTALL.contains("sudo pacman -Sq --needed --noconfirm \\\n git"), "base package install should flow through pacman_install so failures get actionable diagnostics" ); }