Mercurial > crates > nonstick
changeset 104:a2676475e86b default tip
Create the very start of a test suite.
- Creates a new testharness package
- Sets up the outlines of a test suite that will execute there
- A basic container where maybe those tests can execute
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Wed, 25 Jun 2025 16:56:56 -0400 |
parents | dfcd96a74ac4 |
children | |
files | Cargo.toml src/libpam/module.rs testharness/Cargo.toml testharness/container/Containerfile testharness/src/bin/testharness.rs testharness/src/lib.rs testharness/tests/end2end.rs |
diffstat | 7 files changed, 121 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/Cargo.toml Wed Jun 25 00:59:24 2025 -0400 +++ b/Cargo.toml Wed Jun 25 16:56:56 2025 -0400 @@ -1,13 +1,22 @@ +[workspace] +members = ["testharness"] +resolver = "3" + +[workspace.package] +version = "0.0.8-alpha0" +authors = ["Paul Fisher <paul@pfish.zone>"] +repository = "https://hg.pfish.zone/crates/nonstick/" +edition = "2021" + [package] name = "nonstick" description = "PAM bindings for Rust" -version = "0.0.7" -authors = ["Paul Fisher <paul@pfish.zone>", "Anthony Nowell <anowell@gmail.com>" ] -repository = "https://hg.pfish.zone/crates/nonstick/" +version.workspace = true +authors.workspace = true readme = "README.md" keywords = ["pam", "ffi", "linux", "authentication"] license = "MIT" -edition = "2021" +edition.workspace = true [features] default = ["link"]
--- a/src/libpam/module.rs Wed Jun 25 00:59:24 2025 -0400 +++ b/src/libpam/module.rs Wed Jun 25 16:56:56 2025 -0400 @@ -41,12 +41,12 @@ macro_rules! pam_hooks { ($ident:ident) => { mod _pam_hooks_scope { - use std::ffi::{c_char, c_int, CStr}; + use std::ffi::{c_char, c_int, c_void, CStr}; use $crate::{ErrorCode, Flags, LibPamHandle, PamModule}; #[no_mangle] extern "C" fn pam_sm_acct_mgmt( - pamh: *mut libc::c_void, + pamh: *mut c_void, flags: Flags, argc: c_int, argv: *const *const c_char, @@ -61,7 +61,7 @@ #[no_mangle] extern "C" fn pam_sm_authenticate( - pamh: *mut libc::c_void, + pamh: *mut c_void, flags: Flags, argc: c_int, argv: *const *const c_char, @@ -76,7 +76,7 @@ #[no_mangle] extern "C" fn pam_sm_chauthtok( - pamh: *mut libc::c_void, + pamh: *mut c_void, flags: Flags, argc: c_int, argv: *const *const c_char, @@ -91,7 +91,7 @@ #[no_mangle] extern "C" fn pam_sm_close_session( - pamh: *mut libc::c_void, + pamh: *mut c_void, flags: Flags, argc: c_int, argv: *const *const c_char, @@ -106,7 +106,7 @@ #[no_mangle] extern "C" fn pam_sm_open_session( - pamh: *mut libc::c_void, + pamh: *mut c_void, flags: Flags, argc: c_int, argv: *const *const c_char, @@ -121,7 +121,7 @@ #[no_mangle] extern "C" fn pam_sm_setcred( - pamh: *mut libc::c_void, + pamh: *mut c_void, flags: Flags, argc: c_int, argv: *const *const c_char,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testharness/Cargo.toml Wed Jun 25 16:56:56 2025 -0400 @@ -0,0 +1,22 @@ +[package] +name = "nonstick-testharness" +description = "Automatic test harness for the Nonstick PAM library." +publish = false +version.workspace = true +authors.workspace = true +edition.workspace = true + +[lib] +crate-type = ["cdylib"] + +[features] +linux-pam-extensions = ["nonstick/linux-pam-extensions"] +openpam-extensions = ["nonstick/openpam-extensions"] + +[dependencies] +nonstick = { path = ".." } + +[dev-dependencies] +anyhow = "1.0.98" +test-cdylib = "1.1.0" +thiserror = "2.0.12"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testharness/container/Containerfile Wed Jun 25 16:56:56 2025 -0400 @@ -0,0 +1,6 @@ +FROM docker.io/debian:stable + +RUN apt-get -y update \ + && apt-get -y upgrade \ + && apt-get install -y cargo mercurial \ + && apt-get clean \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testharness/src/bin/testharness.rs Wed Jun 25 16:56:56 2025 -0400 @@ -0,0 +1,3 @@ +//! The actual program which runs the tests. + +fn main() {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testharness/src/lib.rs Wed Jun 25 16:56:56 2025 -0400 @@ -0,0 +1,19 @@ +//! The nonstick library +extern crate nonstick; + +use nonstick::{pam_hooks, Flags, PamHandleModule, PamModule}; +use std::ffi::CStr; + +struct TestHarness; + +impl<M: PamHandleModule> PamModule<M> for TestHarness { + fn authenticate(handle: &mut M, args: Vec<&CStr>, flags: Flags) -> nonstick::Result<()> { + Ok(()) + } + + fn account_management(handle: &mut M, args: Vec<&CStr>, flags: Flags) -> nonstick::Result<()> { + Ok(()) + } +} + +pam_hooks!(TestHarness);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testharness/tests/end2end.rs Wed Jun 25 16:56:56 2025 -0400 @@ -0,0 +1,51 @@ +use std::any::Any; +use std::convert::Infallible; +use std::error::Error; +use std::io; +use std::panic::UnwindSafe; +use std::path::{Path, PathBuf}; +use std::{fs, panic}; + +const PAM_CONFIG: &str = "\ +auth required pam_testharness.so +account required pam_testharness.so +password required pam_testharness.so +session required pam_testharness.so +"; +const PAM_CONFIG_PATH: &str = "/etc/pam.d/testharness"; +const PAM_MODULE_PATH: &str = "/lib/security/pam_testharness.so"; + +#[derive(Debug, thiserror::Error)] +enum TestError { + #[error("error in test harness: {0}")] + HarnessError(#[from] io::Error), + #[error("panic in test: {0:?}")] + Panic(Box<dyn Any + Send>), + #[error(transparent)] + TestError(anyhow::Error), +} + +#[test] +fn test_auth_only() -> Result<(), TestError> { + harness(|| Ok::<(), Infallible>(())) +} + +fn harness<E: Error + Send + Sync + 'static>( + test: impl Fn() -> Result<(), E> + UnwindSafe, +) -> Result<(), TestError> { + let dylib_path = test_cdylib::build_current_project(); + let module_path = Path::new(PAM_MODULE_PATH); + let config_path = Path::new(PAM_CONFIG_PATH); + let parent = module_path.parent().unwrap(); + fs::create_dir_all(parent)?; + fs::copy(dylib_path, module_path)?; + fs::write(config_path, PAM_CONFIG)?; + panic::catch_unwind(test) + .map_err(TestError::Panic)? + .map_err(|e| TestError::TestError(e.into()))?; + fs::remove_file(module_path)?; + fs::remove_file(config_path)?; + // If the /lib/security directory can't be removed, that's OK. + let _ = fs::remove_dir(parent); + Ok(()) +}