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(())
+}