]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
doc: document privileged containers and privileged system tests
authorHadi Chokr <hadichokr@icloud.com>
Thu, 12 Feb 2026 11:14:54 +0000 (12:14 +0100)
committerIker Pedrosa <ikerpedrosam@gmail.com>
Mon, 2 Mar 2026 11:55:25 +0000 (12:55 +0100)
Document the distinction between unprivileged and privileged execution
modes for containers and system tests.

Add explicit warnings that privileged tests must never be run on the
host system, as they may mount filesystems, create loop devices, or
modify kernel-visible state.

Provide clear guidance on when privileged tests are acceptable and how
to execute them safely in disposable environments.

Signed-off-by: Hadi Chokr <hadichokr@icloud.com>
doc/contributions/build_install.md
doc/contributions/tests.md

index 4b1b9919300573ce554402f8a2c01e3b6165e8c0..675f11f08fcfea7041b4f4e16459a54d0a9adef3 100644 (file)
@@ -22,7 +22,8 @@ Fedora:
 dnf builddep shadow-utils
 ```
 
-An alternative would be to take a look at the CI workflow [file](../../.github/workflows/runner.yml)
+An alternative would be to take a look at the CI workflow
+[file](../../.github/workflows/runner.yml)
 and get the package names from there. This has the advantage that it
 also includes new dependencies needed for the development version
 which might have not been present in the last release.
@@ -55,14 +56,20 @@ make install
 
 ## Containers
 
-Alternatively, you can use any of the preconfigured container images builders
-to build and install shadow.
+Alternatively, you can use the preconfigured container builders
+to build, install, and test shadow in an isolated environment.
 
-You can either generate a single image by running the following command from
-the root folder of the project (i.e. Alpine):
+The container workflow supports two execution modes:
+
+- Unprivileged (default)
+- Privileged (opt-in, required for BTRFS, mounts, and similar tests)
+
+### Single distribution build
 
 ```
-ansible-playbook share/ansible/playbook.yml -i share/ansible/inventory.ini -e 'distribution=alpine'
+ansible-playbook share/ansible/playbook.yml \
+  -i share/ansible/inventory.ini \
+  -e 'distribution=alpine'
 ```
 
 **Note**: you'll need to install ansible to run this automation.
@@ -70,10 +77,41 @@ ansible-playbook share/ansible/playbook.yml -i share/ansible/inventory.ini -e 'd
 Or generate all of the images with the `container-build.sh` script, as if you
 were running some of the CI checks locally:
 
+### Multiple distributions
+
 ```
 share/container-build.sh
 ```
 
+## Privileged builds and tests
+
+Most development and CI scenarios should use the default (unprivileged)
+mode. It is sufficient for validating core functionality and avoids
+unnecessary exposure to elevated capabilities.
+
+Privileged mode is available for tests that require kernel-level
+operations such as BTRFS subvolumes, loop devices, or filesystem mounts.
+The correct topology is selected automatically based on the mode.
+
+To run privileged builds across all distributions:
+
+```bash
+sudo share/container-build.sh --privileged
+```
+
+Or for a single distribution:
+
+```bash
+sudo ansible-playbook share/ansible/playbook.yml \
+  -i share/ansible/inventory.ini \
+  -e "distribution=fedora" \
+  -e "privileged_mode=true"
+```
+
+Privileged containers should be used in disposable environments (for
+example, a VM or a temporary development system). While they are useful
+for certain scenarios, most development workflows do not require them.
+
 ### Container troubleshooting
 
 When working with containers for testing or development,
@@ -87,6 +125,7 @@ Here are common troubleshooting steps:
   that existed when tests ran.
 
 **Container management:**
+If using a privileged container, you will need to be root to execute these commands.
 - **List containers**: `docker ps -a` to see all containers and their status.
 - **Access container**: `docker exec -it <container-name> bash` to get shell access.
 - **Container logs**: `docker logs <container-name>` to view container output.
index beefc8467e5efe149535b6cdf53855cb6994d84a..dc660cff3a044bd547ff7d16f01755f31e517005 100644 (file)
@@ -52,15 +52,20 @@ The Python framework provides several advantages over Bash tests:
 • **Cross-distribution compatibility**: works on all distributions in CI
   (Alpine, Debian, Fedora and openSUSE)
   unlike Bash tests which only run on Ubuntu.
+  
 • **Proper environment management**: ensures clean setup and teardown
   with environment restoration even when tests fail.
+  
 • **Improved test maintainability**: provides a rich, high-level API
   that reduces complex test code
   and makes tests easier to understand.
+  
 • **Automated artifact collection**: automatically collects logs and artifacts
   when tests finish (even if they fail).
+  
 • **Flexible infrastructure**: supports both VMs and containers for testing
   with local execution capabilities.
+  
 • **Future extensibility**: enables potential filtering by ticket
   or importance and other advanced features.
 
@@ -69,6 +74,55 @@ The Python framework provides several advantages over Bash tests:
 **For all new contributions,
 we recommend using the Python system test framework.**
 
+## Privilege levels
+
+Python system tests are divided into two categories.
+
+### Unprivileged tests (default)
+
+These tests run with standard container permissions and do not require
+elevated capabilities. They are suitable for CI and should be the
+preferred choice for new test development.
+
+### Privileged tests (opt-in)
+
+These tests require elevated capabilities and may perform operations
+such as:
+
+-   Mounting filesystems
+-   Creating loop devices
+-   Working with BTRFS subvolumes
+-   Modifying kernel-visible system state
+
+These capabilities operate at the kernel boundary. If isolation is
+misconfigured, they may affect the host system directly.
+
+Concrete risks include:
+
+-   Accessing and modifying any file on the host system through bind
+    mounts
+-   Interfering with host services by consuming loop devices
+-   Filling host disk space by creating large filesystem images
+-   Leaving orphaned mount points that prevent clean system shutdown
+
+Privileged tests are useful when validating functionality that
+fundamentally depends on those capabilities. However, they should be
+introduced only when no reasonable unprivileged alternative exists.
+
+When writing new tests:
+
+-   Prefer unprivileged designs.
+-   Consider whether the behavior can be validated without mounts or
+    device manipulation.
+-   Use privileged tests as a targeted tool, not the default approach.
+
+Privileged tests should be executed **only** inside:
+
+-   A disposable virtual machine, or
+-   A dedicated privileged container created for testing
+
+They are not intended to run directly on a host system.
+
 #### Contribution guidance
 
 The framework is under active development
@@ -82,6 +136,13 @@ When contributing:
 3. **Missing features**: if you're comfortable implementing missing pytest-mh features,
    contributions are encouraged.
 
+When adding new coverage, prioritize unprivileged test designs.
+Privileged tests should be added only when the feature under test cannot
+be meaningfully validated otherwise.
+
+Review examples in `tests/system/tests/privileged` before introducing
+new privileged scenarios.
+
 #### Running tests
 
 ##### Environment setup
@@ -126,12 +187,15 @@ Instructions are available in the
 
 ##### Execution
 
-Run all Python system tests:
+Run all unprivileged Python system tests:
 
 ```bash
 pytest --mh-config=mhc.yaml --mh-lazy-ssh -v
 ```
 
+Privileged tests are automatically excluded when using `mhc.yaml` because the
+`shadow-privileged` topology is not provisioned. No additional flags are needed.
+
 Run tests in a file:
 
 ```bash
@@ -144,6 +208,13 @@ Run a single test case:
 pytest --mh-config=mhc.yaml --mh-lazy-ssh -v -k test_useradd__add_user
 ```
 
+To run privileged tests, ensure you are **inside a disposable VM or a privileged
+container**, then run:
+
+```bash
+pytest --mh-config=mhc-privileged.yaml --mh-lazy-ssh -v
+```
+
 **Command options explained:**
 - `--mh-config=mhc.yaml`: specifies the multihost configuration file
 - `--mh-lazy-ssh`: enables lazy SSH connections for better performance
@@ -259,6 +330,7 @@ The framework automatically manages shadow system files:
 - Use containers or VMs to avoid system state pollution.
 - Ensure proper cleanup in the framework between test runs.
 - Verify container/VM has necessary privileges for user/group operations.
+- Running privileged tests on the host system, even for local development is a **bad idea**.
 
 For additional information about the testing framework,
 see the [pytest-mh documentation](https://pytest-mh.readthedocs.io).