project: apparmor backends: garden: # The garden backend relies on https://gitlab.com/zygoon/image-garden # TODO: Switch to a released version for better stability. type: adhoc allocate: | # Use just enough RAM to link the parser on a virtual system with # two cores. Using more cores may easily consume more memory, due # to make -j$(nproc), used below than a small CI/CD system is # typically granted. It is better to have more workers than to # have one big worker with lots of resources. export QEMU_MEM_OPTION="-m 1536" export QEMU_SMP_OPTION="-smp 2" ARCH="$(uname -m)" # If a locally built kernel image exist then use it for booting. # Care needs to be taken to make sure the kernel is compatible with # loadable modules present in the file system. if [ -f bzImage ]; then # Create the qcow2/run files before setting custom kernel # options, so that first boot and initialization happen in a # standardized manner. image-garden make "$SPREAD_SYSTEM"."$ARCH".run "$SPREAD_SYSTEM"."$ARCH".qcow2 1>&2 # Pass a simple drive instead of the more elaborate virtio # configuration that is used by default. Some images may not # support virtio enough for booting. export QEMU_STORAGE_OPTION="-drive file=$SPREAD_SYSTEM.$ARCH.qcow2,format=qcow2" # Refrain from passing EFI firmware to qemu so that we boot a # kernel directly and bypass both EFI and BIOS. export QEMU_BOOT_FIRMWARE_OPTION="" # Pass the kernel and cmdline by hand. At present this is tuned # to the Ubuntu cloud images that have the rootfs as the first # partition. exec image-garden allocate "$SPREAD_SYSTEM"."$ARCH" \ -kernel bzImage \ -append 'root=/dev/sda1 ro console=tty1 console=ttyS0' fi # Ask image garden to allocate the system and relay the result back # to spread as either success of failure. exec image-garden allocate "$SPREAD_SYSTEM"."$ARCH" discard: image-garden discard "$SPREAD_SYSTEM_ADDRESS" systems: # All systems except for the one Ubuntu system are marked as # manual. This way we don't accidentally spin up everything when # someone runs spread without knowing better. - opensuse-cloud-tumbleweed: username: opensuse password: opensuse workers: 4 manual: true - debian-cloud-12: username: debian password: debian workers: 4 manual: true - debian-cloud-13: username: debian password: debian workers: 4 manual: true - ubuntu-cloud-22.04: username: ubuntu password: ubuntu workers: 4 manual: true - ubuntu-cloud-24.04: username: ubuntu password: ubuntu workers: 4 manual: true - ubuntu-cloud-24.10: username: ubuntu password: ubuntu workers: 4 - fedora-cloud-41: username: fedora password: fedora exclude: - .git - "*.o" # Files related to spread and image-garden. - "*.qcow2" - "*.iso" - "*.img" - "*.log" - "*.run" - "*.lock" - spread-logs - spread-artifacts # Locally provided kernel image. See allocate section in system backends, # this image, if present, is passed directly to qemu. - bzImage # Copy the project to this path on the test system. # This is also available as $SPREAD_PATH. path: /tmp/apparmor prepare: | # Configure libapparmor but only if a makefile is not already present. # This makes repeated iteration with -reuse much faster, as the chain of # invocations of make below are efficient if nothing needs to be done. if [ ! -f "$SPREAD_PATH"/libraries/libapparmor/Makefile ]; then ( cd $SPREAD_PATH/libraries/libapparmor sh ./autogen.sh && sh ./configure --prefix=/usr --with-perl --with-python ) fi # Build libapparmor. make -C $SPREAD_PATH/libraries/libapparmor -j"$(nproc)" # Build apparmor_parser. make -C $SPREAD_PATH/parser -j"$(nproc)" # Build binary utilities (aa-exec and firends). make -C $SPREAD_PATH/binutils -j"$(nproc)" # Build python utilities. make -C $SPREAD_PATH/utils -j"$(nproc)" # Build apache and pam modules. make -C "$SPREAD_PATH"/changehat/mod_apparmor -j"$(nproc)" make -C "$SPREAD_PATH"/changehat/pam_apparmor -j"$(nproc)" # In case of failure, include the kernel version in the log. debug-each: | uname -a suites: tests/profiles/: summary: Tests that exercise specific application profiles systems: # AppArmor is not enabled in the kernel. - -fedora-cloud-* # variables: # PROFILE_NAME: name of the profile on disk # PROGRAM_NAME: name of the program to execute prepare-each: | rm -f denials.txt # Disable rate-limiting so that we see all denials. sysctl --values kernel.printk_ratelimit >old-ratelimit.txt sysctl --write kernel.printk_ratelimit=0 # Stop auditd so that all denials end up in the ring buffer. if [ "$(systemctl is-active auditd.service)" != inactive ]; then systemctl stop auditd.service touch did-stop-auditd.txt fi # Clear the kernel ring buffer. dmesg --clear # Compute profile name from the name of the task. echo "PROFILE_NAME=${PROFILE_NAME:=$(basename "$SPREAD_TASK")}" "$SPREAD_PATH"/parser/apparmor_parser \ --warn=all \ --replace \ --skip-cache \ --base="$SPREAD_PATH"/profiles/apparmor.d \ "$SPREAD_PATH"/profiles/apparmor.d/"$PROFILE_NAME" 2>parser.txt if [ -s parser.txt ]; then echo "Parser produced warnings:" cat parser.txt exit 1 fi restore-each: | # Compute profile name from the name of the task. echo "PROFILE_NAME=${PROFILE_NAME:=$(basename "$SPREAD_TASK")}" "$SPREAD_PATH"/parser/apparmor_parser \ --base="$SPREAD_PATH"/profiles/apparmor.d \ --remove \ "$SPREAD_PATH"/profiles/apparmor.d/"$PROFILE_NAME" # Restore auditd and old rate-limit. if [ -f did-stop-auditd.txt ]; then systemctl start auditd.service rm -f did-stop-auditd.txt fi if [ -f old-ratelimit.txt ]; then sysctl -w kernel.printk_ratelimit="$(cat old-ratelimit.txt)" rm -f old-ratelimit.txt fi # Check if running the test resulted in any logged denials. if dmesg | grep DENIED > denials.txt; then echo "Denials were emitted during the test" cat denials.txt exit 1 fi debug-each: | echo "PROGRAM_NAME=${PROGRAM_NAME:=$(basename "$SPREAD_TASK")}" command -v "$PROGRAM_NAME" utils/: summary: Unit tests for the Python utilities. prepare: | # Generate apparmor profiles that the tests rely on. make -C "$SPREAD_PATH"/parser/tst gen_xtrans gen_dbus # Spread does not support programmatically generated test variants. # Ensure that the list baked into utils/test/task.yaml contains all # the files matching utils/test/test-*.py fail=0 for V in $SPREAD_PATH/utils/test/test-*.py; do Vdash="$(basename "$V" | sed -e 's,^test-,,' -e 's,\.py$,,')" Vunder="$(basename "$V" | sed -e 's,^test-,,' -e 's,\.py$,,' -e 's,-,_,g')" if ! grep -xF ' TEST/'"$Vunder"': '"$Vdash" "$SPREAD_PATH"/utils/test/task.yaml; then echo "utils/test/task.yaml: missing test variant: TEST/$Vunder: $Vdash" >&2 fail=1 fi done if [ "$fail" -ne 0 ]; then echo "exiting due to missing variants listed above" >&2 exit 1 fi tests/unit/: summary: Unit tests that do not exercise the kernel layer. tests/regression/: summary: Regression tests for parser-kernel interaction. systems: # AppArmor is not enabled in the kernel. - -fedora-cloud-* prepare: | # Spread does not support programmatically generated test variants. # Ensure that the list baked into tests/regression/apparmor/task.yaml # contains all the tests defined in tests/regression/apparmor/Makefile. echo '$(foreach t,$(TESTS),$(info TEST/$t))' | \ make -n -f "$SPREAD_PATH"/tests/regression/apparmor/Makefile -f /dev/stdin | \ grep -F TEST/ | \ cut -d / -f 2 | \ tee apparmor-regression-tests.txt fail=0 while read -r V; do if ! grep -xF ' TEST/'"$V"': 1' "$SPREAD_PATH"/tests/regression/apparmor/task.yaml; then echo "tests/regression/task.yaml: missing test variant: TEST/$V" >&2 fail=1 fi done &2 exit 1 fi # Build all the apparmor regression test programs. make -C "$SPREAD_PATH"/tests/regression/apparmor -j"$(nproc)" restore: | rm -f apparmor-regression-tests.txt tests/snapd/: summary: Tests exercising a subset of behavior of snapd systems: # AppArmor is not enabled in the kernel. - -fedora-cloud-*