From 10ffda7e207f67fd76bed6e289c821570d24824b Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 11:31:02 -0700 Subject: [PATCH 01/59] feat: split SELinux policy into public and test modules Split the trident SELinux policy into two additive modules: 1. trident.pp (public) - ships in trident-selinux RPM, contains all production-required policies. Removed test-only blocks: - Steamboat CI transition (ci_unconfined_t -> trident_t) - Interactive unconfined_run_to transition 2. trident-test.pp (test) - new trident-test-selinux RPM, contains CI and interactive transitions. Must NOT be installed in production. The test module uses SELinux 'require' blocks to reference types from the base module, making it purely additive (no duplication). Changes: - New packaging/selinux-policy-trident-test/ with .te/.fc/.if files - New packaging/rpm/trident-test-selinux.spec for standalone RPM build - Updated Dockerfiles to build both RPMs in the same container - Updated Makefile dependencies - Updated test image definitions to install trident-test-selinux - Added selinux-public-only test config placeholder Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Makefile | 5 +- packaging/docker/Dockerfile.azl3 | 2 + packaging/docker/Dockerfile.full | 2 + packaging/rpm/trident-test-selinux.spec | 65 +++++++++++++++++ .../trident-test.fc | 2 + .../trident-test.if | 8 +++ .../trident-test.te | 40 +++++++++++ packaging/selinux-policy-trident/trident.te | 22 +----- .../selinux-public-only/test-selection.yaml | 14 ++++ .../selinux-public-only/trident-config.yaml | 72 +++++++++++++++++++ .../base/baseimg.yaml | 1 + .../base/baseimg-direct-streaming.yaml | 1 + tests/images/trident-mos/iso.yaml | 6 ++ .../base/baseimg-grub-verity-azure.yaml | 1 + 14 files changed, 220 insertions(+), 21 deletions(-) create mode 100644 packaging/rpm/trident-test-selinux.spec create mode 100644 packaging/selinux-policy-trident-test/trident-test.fc create mode 100644 packaging/selinux-policy-trident-test/trident-test.if create mode 100644 packaging/selinux-policy-trident-test/trident-test.te create mode 100644 tests/e2e_tests/trident_configurations/selinux-public-only/test-selection.yaml create mode 100644 tests/e2e_tests/trident_configurations/selinux-public-only/trident-config.yaml diff --git a/Makefile b/Makefile index 36d87dc0d..a7d72c274 100644 --- a/Makefile +++ b/Makefile @@ -185,7 +185,7 @@ target/azl3/release/trident target/azl3/release/trident-acl-agent: version-vars cargo build --color always --target-dir target/azl3 --release --features dangerous-options,grpc-preview -p trident -p trident-acl-agent # This will do a proper build on azl3, exactly as the pipelines would, with the custom registry and all. -bin/trident-rpms-azl3.tar.gz: packaging/docker/Dockerfile.full packaging/systemd/*.service packaging/rpm/trident.spec artifacts/osmodifier packaging/selinux-policy-trident/* version-vars +bin/trident-rpms-azl3.tar.gz: packaging/docker/Dockerfile.full packaging/systemd/*.service packaging/rpm/trident.spec packaging/rpm/trident-test-selinux.spec artifacts/osmodifier packaging/selinux-policy-trident/* packaging/selinux-policy-trident-test/* version-vars $(eval CARGO_REGISTRIES_BMP_PUBLICPACKAGES_TOKEN := $(shell az account get-access-token --query "join(' ', ['Bearer', accessToken])" --output tsv)) @mkdir -p bin/ @@ -207,7 +207,7 @@ bin/trident-rpms-azl3.tar.gz: packaging/docker/Dockerfile.full packaging/systemd @tar xf $@ -C bin/ # This one does a fast trick-build where we build locally and inject the binary into the container to add it to the RPM. -bin/trident-rpms.tar.gz: packaging/docker/Dockerfile.azl3 packaging/systemd/*.service packaging/rpm/trident.spec artifacts/osmodifier target/release/trident packaging/selinux-policy-trident/* +bin/trident-rpms.tar.gz: packaging/docker/Dockerfile.azl3 packaging/systemd/*.service packaging/rpm/trident.spec packaging/rpm/trident-test-selinux.spec artifacts/osmodifier target/release/trident packaging/selinux-policy-trident/* packaging/selinux-policy-trident-test/* @mkdir -p bin/ @if [ ! -f bin/trident ] || ! cmp -s target/release/trident bin/trident; then \ cp target/release/trident bin/trident; \ @@ -844,6 +844,7 @@ bin/trident-mos.iso: \ tests/images/trident-mos/files/* \ tests/images/trident-mos/post-install.sh \ packaging/selinux-policy-trident/* \ + packaging/selinux-policy-trident-test/* \ tools/cmd/rcp-agent/rcp-agent.service \ bin/rcp-agent @echo "Rebuilding Trident MOS ISO: $@ from $< because of: $?" diff --git a/packaging/docker/Dockerfile.azl3 b/packaging/docker/Dockerfile.azl3 index 0365ffae7..aa90cfa85 100644 --- a/packaging/docker/Dockerfile.azl3 +++ b/packaging/docker/Dockerfile.azl3 @@ -7,6 +7,7 @@ RUN tdnf install -y rpmdevtools openssl-devel clang-devel protobuf-devel rust se WORKDIR /work COPY packaging/rpm/trident.spec . +COPY packaging/rpm/trident-test-selinux.spec . COPY packaging ./packaging COPY bin/trident ./target/release/trident COPY artifacts/osmodifier /usr/src/azl/SOURCES/osmodifier @@ -23,4 +24,5 @@ RUN \ --define="trident_version $TRIDENT_VERSION" \ --define="rpm_ver $RPM_VER" \ --define="rpm_rel $RPM_REL" && \ + rpmbuild -bb --build-in-place trident-test-selinux.spec && \ tar -czvf trident-rpms.tar.gz -C /usr/src/azl ./RPMS \ No newline at end of file diff --git a/packaging/docker/Dockerfile.full b/packaging/docker/Dockerfile.full index 078ed812d..b389e646c 100644 --- a/packaging/docker/Dockerfile.full +++ b/packaging/docker/Dockerfile.full @@ -7,6 +7,7 @@ RUN tdnf install -y rpmdevtools openssl-devel clang-devel protobuf-devel rust-1. WORKDIR /work COPY packaging/rpm/trident.spec . +COPY packaging/rpm/trident-test-selinux.spec . COPY packaging ./packaging COPY artifacts/osmodifier /usr/src/azl/SOURCES/osmodifier @@ -35,6 +36,7 @@ RUN --mount=type=secret,id=registry_token \ --define="trident_version $TRIDENT_VERSION" \ --define="rpm_ver $RPM_VER" \ --define="rpm_rel $RPM_REL" && \ + rpmbuild -bb --build-in-place trident-test-selinux.spec && \ tar -czvf trident-rpms.tar.gz -C /usr/src/azl ./RPMS FROM scratch AS artifact diff --git a/packaging/rpm/trident-test-selinux.spec b/packaging/rpm/trident-test-selinux.spec new file mode 100644 index 000000000..b11d56916 --- /dev/null +++ b/packaging/rpm/trident-test-selinux.spec @@ -0,0 +1,65 @@ +# Test-only SELinux policy module for Trident +# +# This RPM provides additional SELinux permissions needed only in test/CI +# environments. It layers on top of the base trident-selinux module and +# must NOT be installed in production images. +# +# Permissions included: +# - Steamboat/CI exec transition (ci_unconfined_t -> trident_t) +# - Interactive unconfined transition (for manual debugging) + +%global selinuxtype targeted +%global modulename trident-test + +Summary: Trident test-only SELinux policy +Name: trident-test-selinux +Version: 1.0.0 +Release: 1%{?dist} +License: MIT +Vendor: Microsoft Corporation +Group: Applications/System +Distribution: Azure Linux +BuildArch: noarch + +Requires: trident-selinux +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description +Test-only SELinux policy module for Trident. Provides CI/interactive +transitions that are not included in the production trident-selinux package. +This package must NOT be installed in production images. + +%build +mkdir selinux +cp -p packaging/selinux-policy-trident-test/%{modulename}.fc selinux/ +cp -p packaging/selinux-policy-trident-test/%{modulename}.if selinux/ +cp -p packaging/selinux-policy-trident-test/%{modulename}.te selinux/ + +make -f %{_datadir}/selinux/devel/Makefile %{modulename}.pp +bzip2 -9 %{modulename}.pp + +%install +install -D -m 0644 %{modulename}.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2 +install -D -p -m 0644 selinux/%{modulename}.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{modulename}.if + +%files +%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2 +%{_datadir}/selinux/devel/include/distributed/%{modulename}.if +%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} + +%pre +%selinux_relabel_pre -s %{selinuxtype} + +%post +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2 + +%postun +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} %{modulename} +fi + +%posttrans +%selinux_relabel_post -s %{selinuxtype} diff --git a/packaging/selinux-policy-trident-test/trident-test.fc b/packaging/selinux-policy-trident-test/trident-test.fc new file mode 100644 index 000000000..641837cd4 --- /dev/null +++ b/packaging/selinux-policy-trident-test/trident-test.fc @@ -0,0 +1,2 @@ +# trident-test SELinux file contexts +# No additional file contexts needed — the base trident module defines all file labels. diff --git a/packaging/selinux-policy-trident-test/trident-test.if b/packaging/selinux-policy-trident-test/trident-test.if new file mode 100644 index 000000000..5cf60757e --- /dev/null +++ b/packaging/selinux-policy-trident-test/trident-test.if @@ -0,0 +1,8 @@ +## Test-only SELinux interfaces for Trident +## +##

+## This module provides no public interfaces. +## It exists only to satisfy the SELinux build toolchain requirement +## for a .if file alongside the .te and .fc files. +##

+##
diff --git a/packaging/selinux-policy-trident-test/trident-test.te b/packaging/selinux-policy-trident-test/trident-test.te new file mode 100644 index 000000000..e6c094a06 --- /dev/null +++ b/packaging/selinux-policy-trident-test/trident-test.te @@ -0,0 +1,40 @@ +policy_module(trident-test, 1.0.0) + +######################################## +# +# Test-only SELinux policy for Trident +# +# This module provides additional permissions needed only in test/CI +# environments. It layers on top of the base trident policy module +# (trident.pp) and must NOT be installed in production images. +# +# Permissions included: +# - Steamboat/CI exec transition (ci_unconfined_t -> trident_t) +# - Interactive unconfined transition (for manual debugging) +# + +require { + type trident_t; + type trident_exec_t; +} + +# Defines transition from ci_unconfined_t to trident_t when Steamboat executes Trident, as well as +# specific permissions necessary for Steamboat testing +optional_policy(` + require { + type ci_unconfined_t; + role ci_unconfined_r; + } + type_transition ci_unconfined_t trident_exec_t:process trident_t; + allow ci_unconfined_t trident_exec_t:file { getattr open read execute }; + allow trident_t trident_exec_t:file entrypoint; + role ci_unconfined_r types trident_t; + + allow trident_t ci_unconfined_t:fd use; + seutil_run_setfiles(trident_t, ci_unconfined_r); +') + +# Allow transition between unconfined_t and trident_t domains; necessary for an interactive run +optional_policy(` + unconfined_run_to(trident_t, trident_exec_t) +') diff --git a/packaging/selinux-policy-trident/trident.te b/packaging/selinux-policy-trident/trident.te index 0467330cb..196e58b44 100644 --- a/packaging/selinux-policy-trident/trident.te +++ b/packaging/selinux-policy-trident/trident.te @@ -207,26 +207,10 @@ typeattribute trident_t can_change_object_identity; # Defines transition from trident_t to fsadm_t domain when Trident executes fsadm tool (i.e. mkfs) type_transition trident_t fsadm_exec_t:process fsadm_t; -# Defines transition from ci_unconfined_t to trident_t when Steamboat executes Trident, as well as -# specific permissions necessary for Steamboat testing -optional_policy(` - require { - type ci_unconfined_t; - role ci_unconfined_r; - } - type_transition ci_unconfined_t trident_exec_t:process trident_t; - allow ci_unconfined_t trident_exec_t:file { getattr open read execute }; - allow trident_t trident_exec_t:file entrypoint; - role ci_unconfined_r types trident_t; +# NOTE: Test-only transitions (Steamboat CI and interactive unconfined) have been +# moved to the trident-test SELinux module (packaging/selinux-policy-trident-test/). +# They are NOT included in the production trident-selinux RPM. - allow trident_t ci_unconfined_t:fd use; - seutil_run_setfiles(trident_t, ci_unconfined_r); -') - -# Allow transition between unconfined_t and trident_t domains; necessary for an interactive run -optional_policy(` - unconfined_run_to(trident_t, trident_exec_t) -') #============= trident_t ============== # Gives trident_t the following elevated privileges: diff --git a/tests/e2e_tests/trident_configurations/selinux-public-only/test-selection.yaml b/tests/e2e_tests/trident_configurations/selinux-public-only/test-selection.yaml new file mode 100644 index 000000000..56e6c26ff --- /dev/null +++ b/tests/e2e_tests/trident_configurations/selinux-public-only/test-selection.yaml @@ -0,0 +1,14 @@ +compatible: + - base +# This test config validates that trident works with only the public SELinux +# policy (trident-selinux) without the test policy (trident-test-selinux). +# +# It uses the same disk layout as 'base' but is intended to run on an image +# built WITHOUT trident-test-selinux installed. +# +# NOTE: The storm-trident test harness runs trident via SSH (unconfined_t), +# which requires the unconfined_run_to transition in trident-test-selinux. +# Until the test harness supports systemd-activated trident invocation, +# this config should be run on an image that includes the test SELinux policy. +# The value of this config is as a placeholder for future public-policy-only +# validation once the test infrastructure supports it. diff --git a/tests/e2e_tests/trident_configurations/selinux-public-only/trident-config.yaml b/tests/e2e_tests/trident_configurations/selinux-public-only/trident-config.yaml new file mode 100644 index 000000000..6c15a9dcc --- /dev/null +++ b/tests/e2e_tests/trident_configurations/selinux-public-only/trident-config.yaml @@ -0,0 +1,72 @@ +image: + url: http://NETLAUNCH_HOST_ADDRESS/files/regular.cosi + sha384: ignored +storage: + disks: + - id: os + device: /dev/disk/by-path/pci-0000:00:1f.2-ata-2 + partitionTableType: gpt + partitions: + - id: root-a + type: root + size: 8G + - id: root-b + type: root + size: 8G + - id: esp + type: esp + size: 1G + - id: swap + type: swap + size: 2G + - id: home + type: home + size: 1G + - id: trident + type: linux-generic + size: 1G + - id: disk2 + device: /dev/disk/by-path/pci-0000:00:1f.2-ata-3 + partitionTableType: gpt + partitions: [] + abUpdate: + volumePairs: + - id: root + volumeAId: root-a + volumeBId: root-b + filesystems: + - deviceId: trident + source: new + mountPoint: /var/lib/trident + - deviceId: home + source: new + mountPoint: /home + - deviceId: esp + mountPoint: + path: /boot/efi + options: umask=0077 + - deviceId: root + mountPoint: / + swap: + - swap +scripts: + postConfigure: + - name: testing-privilege + runOn: + - clean-install + - ab-update + content: echo 'testing-user ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/testing-user +os: + selinux: + mode: enforcing + netplan: + version: 2 + ethernets: + vmeths: + match: + name: enp* + dhcp4: true + users: + - name: testing-user + sshPublicKeys: [] + sshMode: key-only diff --git a/tests/images/azurelinux-direct-streaming-testimage/base/baseimg.yaml b/tests/images/azurelinux-direct-streaming-testimage/base/baseimg.yaml index 88a8d7b97..865a84c51 100644 --- a/tests/images/azurelinux-direct-streaming-testimage/base/baseimg.yaml +++ b/tests/images/azurelinux-direct-streaming-testimage/base/baseimg.yaml @@ -74,6 +74,7 @@ os: - ntfsprogs # selinux - selinux-policy + - trident-test-selinux services: enable: diff --git a/tests/images/trident-installer/base/baseimg-direct-streaming.yaml b/tests/images/trident-installer/base/baseimg-direct-streaming.yaml index 3ace14fbd..9912cad45 100644 --- a/tests/images/trident-installer/base/baseimg-direct-streaming.yaml +++ b/tests/images/trident-installer/base/baseimg-direct-streaming.yaml @@ -62,6 +62,7 @@ os: - trident # Add trident selinux policy files - trident-selinux + - trident-test-selinux # Add trident-install.service - trident-install-service diff --git a/tests/images/trident-mos/iso.yaml b/tests/images/trident-mos/iso.yaml index 00b235a02..f8e119130 100644 --- a/tests/images/trident-mos/iso.yaml +++ b/tests/images/trident-mos/iso.yaml @@ -81,6 +81,12 @@ os: destination: /usr/share/selinux/packages/trident/trident.fc - source: ../../../packaging/selinux-policy-trident/trident.te destination: /usr/share/selinux/packages/trident/trident.te + - source: ../../../packaging/selinux-policy-trident-test/trident-test.if + destination: /usr/share/selinux/packages/trident-test/trident-test.if + - source: ../../../packaging/selinux-policy-trident-test/trident-test.fc + destination: /usr/share/selinux/packages/trident-test/trident-test.fc + - source: ../../../packaging/selinux-policy-trident-test/trident-test.te + destination: /usr/share/selinux/packages/trident-test/trident-test.te # Trident daemon service files - source: ../../../packaging/systemd/tridentd.socket diff --git a/tests/images/trident-vm-testimage/base/baseimg-grub-verity-azure.yaml b/tests/images/trident-vm-testimage/base/baseimg-grub-verity-azure.yaml index 7da14975f..7023b9c7f 100644 --- a/tests/images/trident-vm-testimage/base/baseimg-grub-verity-azure.yaml +++ b/tests/images/trident-vm-testimage/base/baseimg-grub-verity-azure.yaml @@ -127,6 +127,7 @@ os: - selinux-policy - systemd-udev - trident + - trident-test-selinux - veritysetup - vim - WALinuxAgent From 65ef899d45bedb448cef00428798eb5d46a6a868 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 11:59:32 -0700 Subject: [PATCH 02/59] feat: invoke trident update via systemd service in tests Add trident-update@.service template unit that runs trident update operations (stage/finalize) via systemd domain transition (init_t -> trident_t) instead of direct SSH execution (unconfined_t -> trident_t). The service reads /var/lib/trident/update-env for the config path and log level, and uses the instance name as the --allowed-operations value. Update storm servicing tests to write the env file and start the service instead of running 'sudo trident grpc-client update' directly. This means the update tests now exercise the production SELinux domain transition path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packaging/rpm/trident.spec | 3 ++ packaging/systemd/trident-update@.service | 9 ++++++ tools/storm/servicing/tests/update.go | 35 +++++++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 packaging/systemd/trident-update@.service diff --git a/packaging/rpm/trident.spec b/packaging/rpm/trident.spec index b5cbd1ee4..a13a600fa 100644 --- a/packaging/rpm/trident.spec +++ b/packaging/rpm/trident.spec @@ -89,6 +89,7 @@ and its dependencies for managing the lifecycle of Azure Linux hosts. %endif %{_unitdir}/%{name}d.service %{_unitdir}/%{name}d.socket +%{_unitdir}/%{name}-update@.service %post %systemd_post %{name}d.socket @@ -290,6 +291,8 @@ install -D -m 644 packaging/systemd/%{name}-network.service %{buildroot}%{_unitd # Daemon socket and service install -D -m 644 packaging/systemd/%{name}d.socket %{buildroot}%{_unitdir}/%{name}d.socket install -D -m 644 packaging/systemd/%{name}d.service %{buildroot}%{_unitdir}/%{name}d.service +# Update service template (not enabled by default; used by test infrastructure) +install -D -m 644 packaging/systemd/%{name}-update@.service %{buildroot}%{_unitdir}/%{name}-update@.service mkdir -p %{buildroot}/etc/%{name} diff --git a/packaging/systemd/trident-update@.service b/packaging/systemd/trident-update@.service new file mode 100644 index 000000000..7e1aa7a35 --- /dev/null +++ b/packaging/systemd/trident-update@.service @@ -0,0 +1,9 @@ +[Unit] +Description=Trident Update (%i) +After=network.target network-online.target tridentd.socket + +[Service] +Type=oneshot +EnvironmentFile=/var/lib/trident/update-env +ExecStart=trident grpc-client update ${TRIDENT_LOG_LEVEL} ${UPDATE_CONFIG} --allowed-operations %i +TimeoutStartSec=600 diff --git a/tools/storm/servicing/tests/update.go b/tools/storm/servicing/tests/update.go index 4273a9e2e..39b75e3c8 100644 --- a/tools/storm/servicing/tests/update.go +++ b/tools/storm/servicing/tests/update.go @@ -30,6 +30,37 @@ func Rollback(testConfig stormsvcconfig.TestConfig, vmConfig stormvmconfig.AllVM return innerUpdateLoop(testConfig, vmConfig, true) } +// runTridentUpdateService invokes a trident update operation via the +// trident-update@.service systemd template unit. This runs trident as +// trident_t (via systemd domain transition) rather than unconfined_t +// (via direct SSH execution), matching the production SELinux path. +// +// The operation parameter should be "stage" or "finalize". +func runTridentUpdateService(vmConfig stormvmconfig.VMConfig, vmIP string, updateConfig string, tridentLoggingArg string, operation string) (string, error) { + serviceName := fmt.Sprintf("trident-update@%s.service", operation) + + // Write the environment file that the service unit reads + envContent := fmt.Sprintf("UPDATE_CONFIG=%s\nTRIDENT_LOG_LEVEL=%s\n", updateConfig, tridentLoggingArg) + writeEnvCmd := fmt.Sprintf("printf '%%s' '%s' | sudo tee /var/lib/trident/update-env > /dev/null", envContent) + if _, err := stormssh.SshCommand(vmConfig, vmIP, writeEnvCmd); err != nil { + return "", fmt.Errorf("failed to write update-env for %s: %w", operation, err) + } + + // Reset any previous failed state so the service can be started again + resetCmd := fmt.Sprintf("sudo systemctl reset-failed %s 2>/dev/null; true", serviceName) + stormssh.SshCommand(vmConfig, vmIP, resetCmd) + + // Start the service and wait for it to complete + startCmd := fmt.Sprintf("sudo systemctl start %s 2>&1", serviceName) + _, startErr := stormssh.SshCommandCombinedOutput(vmConfig, vmIP, startCmd) + + // Capture the service output from the journal + journalCmd := fmt.Sprintf("sudo journalctl -u %s --no-pager -o cat 2>&1", serviceName) + journalOutput, _ := stormssh.SshCommandCombinedOutput(vmConfig, vmIP, journalCmd) + + return journalOutput, startErr +} + func innerUpdateLoop(testConfig stormsvcconfig.TestConfig, vmConfig stormvmconfig.AllVMConfig, rollback bool) error { // Create context to ensure goroutines exit cleanly ctx, cancel := context.WithCancel(context.Background()) @@ -225,7 +256,7 @@ func innerUpdateLoop(testConfig stormsvcconfig.TestConfig, vmConfig stormvmconfi } logrus.Tracef("Running Trident update staging command on VM") - combinedStagingOutput, stageErr := stormssh.SshCommandCombinedOutput(vmConfig.VMConfig, vmIP, fmt.Sprintf("sudo trident grpc-client update %s %s --allowed-operations stage", tridentLoggingArg, updateConfig)) + combinedStagingOutput, stageErr := runTridentUpdateService(vmConfig.VMConfig, vmIP, updateConfig, tridentLoggingArg, "stage") if testConfig.Verbose { logrus.Tracef("Staging output for iteration %d:\n%s", i, combinedStagingOutput) } @@ -285,7 +316,7 @@ func innerUpdateLoop(testConfig stormsvcconfig.TestConfig, vmConfig stormvmconfi logrus.Tracef("Pre-reboot uptime --since for iteration %d: %s", i, preRebootUptime) } - combinedFinalizeOutput, finalizeErr := stormssh.SshCommandCombinedOutput(vmConfig.VMConfig, vmIP, fmt.Sprintf("sudo trident grpc-client update %s %s --allowed-operations finalize", tridentLoggingArg, updateConfig)) + combinedFinalizeOutput, finalizeErr := runTridentUpdateService(vmConfig.VMConfig, vmIP, updateConfig, tridentLoggingArg, "finalize") if testConfig.Verbose { logrus.Tracef("Finalize output for iteration %d:\n%s\n%v", i, combinedFinalizeOutput, finalizeErr) } From 0daac44cdcc0f525d0a746053f67cc1b4b9acd87 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 12:38:52 -0700 Subject: [PATCH 03/59] fix: use mkdir -p for selinux build directory The selinux/ directory may already exist when rpmbuild runs with --build-in-place (e.g., from the test policy build running in the same working directory). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packaging/rpm/trident-test-selinux.spec | 2 +- packaging/rpm/trident.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/rpm/trident-test-selinux.spec b/packaging/rpm/trident-test-selinux.spec index b11d56916..4b81f3598 100644 --- a/packaging/rpm/trident-test-selinux.spec +++ b/packaging/rpm/trident-test-selinux.spec @@ -33,7 +33,7 @@ transitions that are not included in the production trident-selinux package. This package must NOT be installed in production images. %build -mkdir selinux +mkdir -p selinux cp -p packaging/selinux-policy-trident-test/%{modulename}.fc selinux/ cp -p packaging/selinux-policy-trident-test/%{modulename}.if selinux/ cp -p packaging/selinux-policy-trident-test/%{modulename}.te selinux/ diff --git a/packaging/rpm/trident.spec b/packaging/rpm/trident.spec index a13a600fa..338644188 100644 --- a/packaging/rpm/trident.spec +++ b/packaging/rpm/trident.spec @@ -245,7 +245,7 @@ export TRIDENT_VERSION="%{trident_version}" %endif cargo build --release -mkdir selinux +mkdir -p selinux cp -p packaging/selinux-policy-trident/trident.fc selinux/ cp -p packaging/selinux-policy-trident/trident.if selinux/ cp -p packaging/selinux-policy-trident/trident.te selinux/ From feafb4ff75436114c3fa51af463d350c7eec6cf7 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 13:40:50 -0700 Subject: [PATCH 04/59] fix: split verbosity into separate env var for systemd systemd EnvironmentFile doesn't handle multi-word values in ExecStart correctly. Split TRIDENT_LOG_LEVEL='-v DEBUG' into separate TRIDENT_VERBOSITY=DEBUG variable and hardcode '-v' in the service unit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packaging/systemd/trident-update@.service | 2 +- tools/storm/servicing/tests/update.go | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packaging/systemd/trident-update@.service b/packaging/systemd/trident-update@.service index 7e1aa7a35..28596819c 100644 --- a/packaging/systemd/trident-update@.service +++ b/packaging/systemd/trident-update@.service @@ -5,5 +5,5 @@ After=network.target network-online.target tridentd.socket [Service] Type=oneshot EnvironmentFile=/var/lib/trident/update-env -ExecStart=trident grpc-client update ${TRIDENT_LOG_LEVEL} ${UPDATE_CONFIG} --allowed-operations %i +ExecStart=trident grpc-client update -v ${TRIDENT_VERBOSITY} ${UPDATE_CONFIG} --allowed-operations %i TimeoutStartSec=600 diff --git a/tools/storm/servicing/tests/update.go b/tools/storm/servicing/tests/update.go index 39b75e3c8..dc07cd9f1 100644 --- a/tools/storm/servicing/tests/update.go +++ b/tools/storm/servicing/tests/update.go @@ -39,8 +39,14 @@ func Rollback(testConfig stormsvcconfig.TestConfig, vmConfig stormvmconfig.AllVM func runTridentUpdateService(vmConfig stormvmconfig.VMConfig, vmIP string, updateConfig string, tridentLoggingArg string, operation string) (string, error) { serviceName := fmt.Sprintf("trident-update@%s.service", operation) + // Extract verbosity level from tridentLoggingArg (e.g., "-v WARN" -> "WARN") + verbosity := "WARN" + if strings.Contains(tridentLoggingArg, "DEBUG") { + verbosity = "DEBUG" + } + // Write the environment file that the service unit reads - envContent := fmt.Sprintf("UPDATE_CONFIG=%s\nTRIDENT_LOG_LEVEL=%s\n", updateConfig, tridentLoggingArg) + envContent := fmt.Sprintf("UPDATE_CONFIG=%s\nTRIDENT_VERBOSITY=%s\n", updateConfig, verbosity) writeEnvCmd := fmt.Sprintf("printf '%%s' '%s' | sudo tee /var/lib/trident/update-env > /dev/null", envContent) if _, err := stormssh.SshCommand(vmConfig, vmIP, writeEnvCmd); err != nil { return "", fmt.Errorf("failed to write update-env for %s: %w", operation, err) From bac962cc6665820ce81f29d45e0f02c5b2db403c Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 13:54:28 -0700 Subject: [PATCH 05/59] feat: add SELinux validation test images, revert update.go changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add dedicated SELinux test images (tests/images/trident-selinux-testimage/) that use SELinux enforcing mode with ONLY the public trident-selinux policy (no trident-test-selinux). The base image includes trident-update@.service for systemd-activated updates. Revert the update.go changes that switched all servicing tests to use systemd invocation — most tests have SELinux disabled so the change added complexity without benefit. The systemd update path will be validated through the dedicated SELinux test images instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packaging/rpm/trident.spec | 3 - packaging/systemd/trident-update@.service | 3 + tests/images/testimages.py | 16 ++ .../base/baseimg.yaml | 182 ++++++++++++++++++ .../base/updateimg.yaml | 154 +++++++++++++++ tools/storm/servicing/tests/update.go | 41 +--- 6 files changed, 357 insertions(+), 42 deletions(-) create mode 100644 tests/images/trident-selinux-testimage/base/baseimg.yaml create mode 100644 tests/images/trident-selinux-testimage/base/updateimg.yaml diff --git a/packaging/rpm/trident.spec b/packaging/rpm/trident.spec index 338644188..1f0ac1433 100644 --- a/packaging/rpm/trident.spec +++ b/packaging/rpm/trident.spec @@ -89,7 +89,6 @@ and its dependencies for managing the lifecycle of Azure Linux hosts. %endif %{_unitdir}/%{name}d.service %{_unitdir}/%{name}d.socket -%{_unitdir}/%{name}-update@.service %post %systemd_post %{name}d.socket @@ -291,8 +290,6 @@ install -D -m 644 packaging/systemd/%{name}-network.service %{buildroot}%{_unitd # Daemon socket and service install -D -m 644 packaging/systemd/%{name}d.socket %{buildroot}%{_unitdir}/%{name}d.socket install -D -m 644 packaging/systemd/%{name}d.service %{buildroot}%{_unitdir}/%{name}d.service -# Update service template (not enabled by default; used by test infrastructure) -install -D -m 644 packaging/systemd/%{name}-update@.service %{buildroot}%{_unitdir}/%{name}-update@.service mkdir -p %{buildroot}/etc/%{name} diff --git a/packaging/systemd/trident-update@.service b/packaging/systemd/trident-update@.service index 28596819c..b623f7f7a 100644 --- a/packaging/systemd/trident-update@.service +++ b/packaging/systemd/trident-update@.service @@ -7,3 +7,6 @@ Type=oneshot EnvironmentFile=/var/lib/trident/update-env ExecStart=trident grpc-client update -v ${TRIDENT_VERBOSITY} ${UPDATE_CONFIG} --allowed-operations %i TimeoutStartSec=600 + +[Install] +WantedBy=multi-user.target diff --git a/tests/images/testimages.py b/tests/images/testimages.py index 09fefe00d..fc7dd6a37 100755 --- a/tests/images/testimages.py +++ b/tests/images/testimages.py @@ -95,6 +95,22 @@ requires_ukify=True, ssh_key="files/id_rsa.pub", ), + ImageConfig( + "trident-selinux-testimage", + base_image=BaseImage.QEMU_GUEST, + config="trident-selinux-testimage", + config_file="base/baseimg.yaml", + requires_ukify=True, + ssh_key="../../trident-vm-testimage/base/files/id_rsa.pub", + ), + ImageConfig( + "trident-selinux-testimage-update", + base_image=BaseImage.QEMU_GUEST, + config="trident-selinux-testimage", + config_file="base/updateimg.yaml", + requires_ukify=True, + ssh_key="../../trident-vm-testimage/base/files/id_rsa.pub", + ), ImageConfig( "trident-vm-grub-verity-azure-testimage", base_image=BaseImage.CORE_SELINUX, diff --git a/tests/images/trident-selinux-testimage/base/baseimg.yaml b/tests/images/trident-selinux-testimage/base/baseimg.yaml new file mode 100644 index 000000000..4cdc8b716 --- /dev/null +++ b/tests/images/trident-selinux-testimage/base/baseimg.yaml @@ -0,0 +1,182 @@ +# SELinux validation base image. +# Based on baseimg-usr-verity.yaml but with SELinux ENFORCING and only the +# public trident-selinux policy (no trident-test-selinux). Validates that +# the production SELinux policy is sufficient for the systemd-activated +# update path. +storage: + bootType: efi + + disks: + - partitionTableType: gpt + partitions: + - id: esp + type: esp + label: esp + size: 512M + + - id: boot-a + size: 256M + + - id: boot-b + size: 256M + + - id: root-a + size: 4G + + - id: root-b + size: 4G + + - id: usr-a + size: 1G + + - id: usr-b + size: 1G + + - id: usr-hash-a + size: 128M + + - id: usr-hash-b + size: 128M + + - id: trident + label: trident + size: 512M + + - id: home + label: home + size: 1G + + - id: srv + label: srv + size: 128M + + verity: + - id: usrverity + name: usr + dataDeviceId: usr-a + hashDeviceId: usr-hash-a + dataDeviceMountIdType: uuid + hashDeviceMountIdType: uuid + + filesystems: + - deviceId: esp + type: fat32 + mountPoint: + idType: part-label + path: /boot/efi + options: umask=0077 + + - deviceId: boot-a + type: ext4 + mountPoint: + idType: uuid + path: /boot + + - deviceId: usrverity + type: ext4 + mountPoint: + path: /usr + options: defaults,ro + + - deviceId: root-a + type: ext4 + mountPoint: + idType: uuid + path: / + + - deviceId: trident + type: ext4 + mountPoint: + idType: part-label + path: /var/lib/trident + + - deviceId: home + type: ext4 + mountPoint: + idType: part-label + path: /home + + - deviceId: srv + type: ext4 + mountPoint: + idType: part-label + path: /srv + +os: + bootloader: + resetType: hard-reset + hostname: trident-selinux-testimg + + selinux: + mode: enforcing + + uki: + mode: create + kernelCommandLine: + extraCommandLine: + - console=tty0 + - console=tty1 + - console=ttyS0 + - rd.debug + - loglevel=6 + - log_buf_len=1M + - systemd.journald.forward_to_console=1 + - rd.hostonly=0 + + packages: + install: + - device-mapper + - dnf + - efibootmgr + - iproute + - iptables + - jq + - kexec-tools + - lvm2 + - openssh-server + - selinux-policy + - systemd-boot + - systemd-udev + - trident-service + # NOTE: trident-test-selinux is intentionally NOT installed. + # This image validates the production SELinux policy alone. + - veritysetup + - vim + - netplan + remove: + - grub2-efi-binary + + additionalFiles: + - source: ../../trident-vm-testimage/base/files/99-dhcp-eth0.network + destination: /etc/systemd/network/99-dhcp-eth0.network + - source: ../../trident-vm-testimage/base/files/sudoers-wheel + destination: /etc/sudoers.d/wheel + # Trident update service template — runs updates via systemd domain + # transition (init_t -> trident_t), exercising the production SELinux path. + - source: ../../../../packaging/systemd/trident-update@.service + destination: /usr/lib/systemd/system/trident-update@.service + + services: + enable: + - kdump + - trident + - tridentd.socket + + users: + - name: testuser + sshPublicKeyPaths: + - ../../trident-vm-testimage/base/files/id_rsa.pub + secondaryGroups: + - wheel + +scripts: + postCustomization: + - path: ../../trident-vm-testimage/base/scripts/post-install.sh + - path: ../../trident-vm-testimage/base/scripts/update-host-status.sh + - path: ../../trident-vm-testimage/base/scripts/prepare-update-config-verity.sh + arguments: + - uki + - path: ../../trident-vm-testimage/base/scripts/duid-type-to-link-layer.sh + +previewFeatures: + - uki diff --git a/tests/images/trident-selinux-testimage/base/updateimg.yaml b/tests/images/trident-selinux-testimage/base/updateimg.yaml new file mode 100644 index 000000000..207fbbccb --- /dev/null +++ b/tests/images/trident-selinux-testimage/base/updateimg.yaml @@ -0,0 +1,154 @@ +# SELinux validation update image. +# Paired with baseimg.yaml — uses enforcing SELinux with public policy only. +storage: + bootType: efi + + disks: + - partitionTableType: gpt + maxSize: 7G + partitions: + - id: esp + type: esp + size: 8M + + - id: boot + size: 256M + + - id: root + size: 4G + + - id: root-hash + size: 128M + + - id: var + size: 1G + + - id: trident-overlay + size: 32M + + - id: srv + size: 1G + + - id: home + size: 32M + + verity: + - id: rootverity + name: root + dataDeviceId: root + hashDeviceId: root-hash + dataDeviceMountIdType: uuid + hashDeviceMountIdType: uuid + + filesystems: + - deviceId: esp + type: fat32 + mountPoint: + options: umask=0077 + path: /boot/efi + + - deviceId: boot + type: ext4 + mountPoint: + path: /boot + + - deviceId: rootverity + type: ext4 + mountPoint: + path: / + options: defaults,ro + + - deviceId: var + type: ext4 + mountPoint: + path: /var + + - deviceId: trident-overlay + type: ext4 + mountPoint: + path: /var/lib/trident-overlay + + - deviceId: srv + type: ext4 + mountPoint: + path: /srv + + - deviceId: home + type: ext4 + mountPoint: + path: /home + +os: + bootloader: + resetType: hard-reset + hostname: trident-selinux-testimg + + selinux: + mode: enforcing + + kernelCommandLine: + extraCommandLine: + - console=tty0 + - console=tty1 + - console=ttyS0 + - rd.debug + - loglevel=6 + - log_buf_len=1M + - systemd.journald.forward_to_console=1 + + packages: + install: + - curl + - device-mapper + - dnf + - dracut-overlayfs + - efibootmgr + - grub2-efi-binary-noprefix + - iproute + - iptables + - jq + - kexec-tools + - lsof + - lvm2 + - netplan + - openssh-server + - selinux-policy + - systemd-udev + - trident-service + # NOTE: trident-test-selinux is intentionally NOT installed. + - veritysetup + - vim + - WALinuxAgent + remove: + - grub2-efi-binary + + additionalFiles: + - source: ../../trident-vm-testimage/base/files/etc-mount.service + destination: /etc/systemd/system/etc-mount.service + - source: ../../trident-vm-testimage/base/files/etc-mount.sh + destination: /usr/local/bin/etc-mount.sh + - source: ../../trident-vm-testimage/base/files/sudoers-wheel + destination: /etc/sudoers.d/wheel + - source: ../../trident-vm-testimage/base/files/99-dhcp-eth0.network + destination: /etc/systemd/network/99-dhcp-eth0.network + - source: ../../trident-vm-testimage/base/files/use-grpc-client-commit.conf + destination: /etc/systemd/system/trident.service.d/override.conf + + services: + enable: + - etc-mount + - kdump + - trident + - tridentd.socket + + users: + - name: testuser + secondaryGroups: + - wheel + +scripts: + postCustomization: + - path: ../../trident-vm-testimage/base/scripts/post-install.sh + - path: ../../trident-vm-testimage/base/scripts/ssh-move-host-keys.sh + - path: ../../trident-vm-testimage/base/scripts/update-os-release.sh + - path: ../../trident-vm-testimage/base/scripts/duid-type-to-link-layer.sh diff --git a/tools/storm/servicing/tests/update.go b/tools/storm/servicing/tests/update.go index dc07cd9f1..4273a9e2e 100644 --- a/tools/storm/servicing/tests/update.go +++ b/tools/storm/servicing/tests/update.go @@ -30,43 +30,6 @@ func Rollback(testConfig stormsvcconfig.TestConfig, vmConfig stormvmconfig.AllVM return innerUpdateLoop(testConfig, vmConfig, true) } -// runTridentUpdateService invokes a trident update operation via the -// trident-update@.service systemd template unit. This runs trident as -// trident_t (via systemd domain transition) rather than unconfined_t -// (via direct SSH execution), matching the production SELinux path. -// -// The operation parameter should be "stage" or "finalize". -func runTridentUpdateService(vmConfig stormvmconfig.VMConfig, vmIP string, updateConfig string, tridentLoggingArg string, operation string) (string, error) { - serviceName := fmt.Sprintf("trident-update@%s.service", operation) - - // Extract verbosity level from tridentLoggingArg (e.g., "-v WARN" -> "WARN") - verbosity := "WARN" - if strings.Contains(tridentLoggingArg, "DEBUG") { - verbosity = "DEBUG" - } - - // Write the environment file that the service unit reads - envContent := fmt.Sprintf("UPDATE_CONFIG=%s\nTRIDENT_VERBOSITY=%s\n", updateConfig, verbosity) - writeEnvCmd := fmt.Sprintf("printf '%%s' '%s' | sudo tee /var/lib/trident/update-env > /dev/null", envContent) - if _, err := stormssh.SshCommand(vmConfig, vmIP, writeEnvCmd); err != nil { - return "", fmt.Errorf("failed to write update-env for %s: %w", operation, err) - } - - // Reset any previous failed state so the service can be started again - resetCmd := fmt.Sprintf("sudo systemctl reset-failed %s 2>/dev/null; true", serviceName) - stormssh.SshCommand(vmConfig, vmIP, resetCmd) - - // Start the service and wait for it to complete - startCmd := fmt.Sprintf("sudo systemctl start %s 2>&1", serviceName) - _, startErr := stormssh.SshCommandCombinedOutput(vmConfig, vmIP, startCmd) - - // Capture the service output from the journal - journalCmd := fmt.Sprintf("sudo journalctl -u %s --no-pager -o cat 2>&1", serviceName) - journalOutput, _ := stormssh.SshCommandCombinedOutput(vmConfig, vmIP, journalCmd) - - return journalOutput, startErr -} - func innerUpdateLoop(testConfig stormsvcconfig.TestConfig, vmConfig stormvmconfig.AllVMConfig, rollback bool) error { // Create context to ensure goroutines exit cleanly ctx, cancel := context.WithCancel(context.Background()) @@ -262,7 +225,7 @@ func innerUpdateLoop(testConfig stormsvcconfig.TestConfig, vmConfig stormvmconfi } logrus.Tracef("Running Trident update staging command on VM") - combinedStagingOutput, stageErr := runTridentUpdateService(vmConfig.VMConfig, vmIP, updateConfig, tridentLoggingArg, "stage") + combinedStagingOutput, stageErr := stormssh.SshCommandCombinedOutput(vmConfig.VMConfig, vmIP, fmt.Sprintf("sudo trident grpc-client update %s %s --allowed-operations stage", tridentLoggingArg, updateConfig)) if testConfig.Verbose { logrus.Tracef("Staging output for iteration %d:\n%s", i, combinedStagingOutput) } @@ -322,7 +285,7 @@ func innerUpdateLoop(testConfig stormsvcconfig.TestConfig, vmConfig stormvmconfi logrus.Tracef("Pre-reboot uptime --since for iteration %d: %s", i, preRebootUptime) } - combinedFinalizeOutput, finalizeErr := runTridentUpdateService(vmConfig.VMConfig, vmIP, updateConfig, tridentLoggingArg, "finalize") + combinedFinalizeOutput, finalizeErr := stormssh.SshCommandCombinedOutput(vmConfig.VMConfig, vmIP, fmt.Sprintf("sudo trident grpc-client update %s %s --allowed-operations finalize", tridentLoggingArg, updateConfig)) if testConfig.Verbose { logrus.Tracef("Finalize output for iteration %d:\n%s\n%v", i, combinedFinalizeOutput, finalizeErr) } From 6b1cb96b03f864ff8358ab57c70e33b85684be32 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 14:07:15 -0700 Subject: [PATCH 06/59] feat: add SELinux update validation pipeline stage New testing_selinux/selinux-update-testing.yml stage that: 1. Builds SELinux-enforcing UKI images with public policy only 2. Installs base image on QEMU VM via netlaunch 3. Runs A/B update via trident-update@stage/finalize.service (systemd) 4. Validates VM reboots and SELinux remains enforcing with no AVCs Added to pr-e2e pipeline in e2e-template.yml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .pipelines/templates/e2e-template.yml | 3 + .../selinux-update-testing.yml | 236 ++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 .pipelines/templates/stages/testing_selinux/selinux-update-testing.yml diff --git a/.pipelines/templates/e2e-template.yml b/.pipelines/templates/e2e-template.yml index 52248b10c..c49c67456 100644 --- a/.pipelines/templates/e2e-template.yml +++ b/.pipelines/templates/e2e-template.yml @@ -421,6 +421,9 @@ stages: micVersion: ${{ parameters.micVersion }} testSecureBoot: ${{ parameters.testSecureBoot }} + # SELinux policy validation — tests update with public policy only + - template: stages/testing_selinux/selinux-update-testing.yml + # TESTING stages for AZL-VALIDATION - ${{ if eq(parameters.stageType, 'azl-validation') }}: # VM Testing (host, post_merge) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml new file mode 100644 index 000000000..ded369afe --- /dev/null +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -0,0 +1,236 @@ +# SELinux Policy Validation Stage +# +# Validates that the public trident-selinux policy (without trident-test-selinux) +# is sufficient for the production systemd-activated update path. +# +# This stage: +# 1. Builds a SELinux-enforcing UKI image with only the public policy +# 2. Installs the image on a QEMU VM via netlaunch +# 3. Runs a single A/B update cycle via trident-update@.service (systemd) +# 4. Verifies the VM rebooted and came back up after the update +# +# The trident-update@.service runs as trident_t via systemd domain transition +# (init_t -> trident_t), which is the production SELinux path. + +parameters: + - name: dependsOnStages + type: object + default: [] + +stages: + - stage: SELinuxUpdateValidation + displayName: SELinux Policy Update Validation + dependsOn: + - PrepareSSHKeys + - GetTridentBinaries_rpms_amd64 + - BuildingTools + - ${{ each stage in parameters.dependsOnStages }}: + - ${{ stage }} + + jobs: + # Build the SELinux test images + - template: ../trident_images/trident-testimg-template.yml + parameters: + target: artifacts/trident-selinux-testimage.qcow2 + label: selinux-base + + - template: ../trident_images/trident-testimg-template.yml + parameters: + target: artifacts/trident-selinux-testimage-update.cosi + label: selinux-update + + # Run the SELinux update validation test + - job: SELinuxUpdateTest + displayName: SELinux Update Test + dependsOn: + - TridentTestImg_selinux_base + - TridentTestImg_selinux_update + timeoutInMinutes: 30 + pool: + type: linux + name: trident-ubuntu-1es-pool-eastus2 + hostArchitecture: amd64 + + variables: + - name: ob_outputDirectory + value: /tmp/selinux_test_logs + - name: ob_artifactBaseName + value: selinux_update_test_$(System.JobAttempt) + + steps: + - template: ../common_tasks/checkout_trident.yml + + - template: ../testing_common/download-tools.yml + + - bash: | + set -eux + mkdir -p artifacts/iso artifacts/test-image + + # Download the built images from pipeline artifacts + echo "Downloading SELinux test images..." + cp $(System.ArtifactsDirectory)/selinux-base/trident-selinux-testimage.qcow2 artifacts/ + cp $(System.ArtifactsDirectory)/selinux-update/trident-selinux-testimage-update.cosi artifacts/test-image/usrverity.cosi + workingDirectory: $(TRIDENT_SOURCE_DIR) + displayName: "Download SELinux test images" + + - bash: | + set -eux + + # Disable virtlogd rollover + echo "max_size = 0" | sudo tee -a /etc/libvirt/virtlogd.conf + sudo systemctl restart virtlogd.socket + + ./tools/virt-deploy create --mem 12 --disks 32,32 + workingDirectory: $(TRIDENT_SOURCE_DIR) + displayName: "Create QEMU VM" + + - bash: | + set -eux + + TRIDENT_CONFIG="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/trident_configurations/usr-verity/trident-config.yaml" + SIGNING_CERT="" + CA_CERT_PATH="$(System.ArtifactsDirectory)/selinux-base/ca_cert.pem" + if [ -f "$CA_CERT_PATH" ]; then + SIGNING_CERT="--signing-cert $CA_CERT_PATH" + fi + + ./bin/netlaunch \ + --iso ./artifacts/iso/trident-installer.iso \ + --config $(TRIDENT_SOURCE_DIR)/tools/vm-netlaunch.yaml \ + --trident "$TRIDENT_CONFIG" \ + --servefolder ./artifacts/test-image \ + --logstream \ + --trace-file $(TRIDENT_SOURCE_DIR)/trident-selinux-metrics.jsonl \ + --force-color \ + --full-logstream logstream-full.log \ + --wait-for-provisioned-state \ + $SIGNING_CERT \ + --port 4000 2>&1 | tee ./selinux-clean-install.log + workingDirectory: $(TRIDENT_SOURCE_DIR) + displayName: "🚀 Install base image via netlaunch" + timeoutInMinutes: 20 + + - bash: | + set -eux + sudo ./bin/storm-trident helper wait-for-login -a \ + --vm-name "$(jq -r '.virtualmachines[0].name' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json)" \ + --artifacts-folder "$(ob_outputDirectory)" + timeoutInMinutes: 5 + condition: succeededOrFailed() + workingDirectory: $(TRIDENT_SOURCE_DIR) + displayName: "📄 Verify VM booted" + + - bash: | + set -eux + HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) + SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + + echo "=== Check SELinux is enforcing ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo getenforce' + + echo "=== Verify trident-test-selinux is NOT installed ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo semodule -l | grep trident' + + echo "=== Check trident-update@.service exists ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'systemctl cat trident-update@stage.service' + workingDirectory: $(TRIDENT_SOURCE_DIR) + displayName: "🔒 Verify SELinux state" + + - bash: | + set -eux + HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) + SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + + echo "=== Write update environment file ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + "printf 'UPDATE_CONFIG=/var/lib/trident/update-config.yaml\nTRIDENT_VERBOSITY=DEBUG\n' | sudo tee /var/lib/trident/update-env" + + echo "=== Start trident-update@stage.service ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo systemctl start trident-update@stage.service' + + echo "=== Stage service completed successfully ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo journalctl -u trident-update@stage.service --no-pager' + workingDirectory: $(TRIDENT_SOURCE_DIR) + displayName: "🔄 Run update stage via systemd" + timeoutInMinutes: 10 + + - bash: | + set -eux + HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) + SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + + echo "=== Start trident-update@finalize.service ===" + # Finalize triggers a reboot, so the SSH connection will drop. + # Use a timeout and ignore the connection drop. + ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=5 -o ServerAliveCountMax=1 \ + -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo systemctl start trident-update@finalize.service' || true + + echo "=== Waiting for VM to reboot ===" + sleep 10 + + sudo ./bin/storm-trident helper wait-for-login -a \ + --vm-name "$(jq -r '.virtualmachines[0].name' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json)" \ + --artifacts-folder "$(ob_outputDirectory)" + workingDirectory: $(TRIDENT_SOURCE_DIR) + displayName: "🔄 Run update finalize via systemd" + timeoutInMinutes: 10 + + - bash: | + set -eux + HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) + SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + + echo "=== Verify VM is up after update ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'hostname && uptime' + + echo "=== Check SELinux is still enforcing ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo getenforce' + + echo "=== Check for SELinux denials ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo ausearch -m avc --start recent 2>&1 || echo "No recent AVC denials"' + + echo "=== Check active volume ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo trident get 2>&1 || echo "trident get completed"' + + echo "=== SELinux update validation PASSED ===" + workingDirectory: $(TRIDENT_SOURCE_DIR) + displayName: "✅ Validate update succeeded" + + - bash: | + set -eux + HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) + SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + + mkdir -p $(ob_outputDirectory) + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo ausearch -m avc 2>&1' > $(ob_outputDirectory)/audit-avc.log || true + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo journalctl --no-pager 2>&1' > $(ob_outputDirectory)/journal.log || true + workingDirectory: $(TRIDENT_SOURCE_DIR) + condition: succeededOrFailed() + displayName: "📄 Collect logs" + + - bash: | + set -eux + sudo virsh shutdown virtdeploy-vm-0 + mkdir -p $(ob_outputDirectory) + sudo cp /var/lib/libvirt/images/virtdeploy-pool/virtdeploy-vm-0-0-volume.qcow2 $(ob_outputDirectory)/ + sudo zstd -T0 $(ob_outputDirectory)/virtdeploy-vm-0-0-volume.qcow2 + workingDirectory: $(TRIDENT_SOURCE_DIR) + condition: failed() + displayName: "Publish OS disk on failure" + + - template: ../testing_common/fix-output-directory-for-one-branch-step.yml + parameters: + outputDir: $(ob_outputDirectory) + condition: always() From 67fd1fd1c9cec700ee53ade37d71254a61f209c8 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 14:09:48 -0700 Subject: [PATCH 07/59] cleanup: remove unused selinux-public-only test config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test config was a placeholder that's no longer needed — the SELinux validation is handled by the dedicated pipeline stage, not the e2e test matrix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-public-only/test-selection.yaml | 14 ---- .../selinux-public-only/trident-config.yaml | 72 ------------------- 2 files changed, 86 deletions(-) delete mode 100644 tests/e2e_tests/trident_configurations/selinux-public-only/test-selection.yaml delete mode 100644 tests/e2e_tests/trident_configurations/selinux-public-only/trident-config.yaml diff --git a/tests/e2e_tests/trident_configurations/selinux-public-only/test-selection.yaml b/tests/e2e_tests/trident_configurations/selinux-public-only/test-selection.yaml deleted file mode 100644 index 56e6c26ff..000000000 --- a/tests/e2e_tests/trident_configurations/selinux-public-only/test-selection.yaml +++ /dev/null @@ -1,14 +0,0 @@ -compatible: - - base -# This test config validates that trident works with only the public SELinux -# policy (trident-selinux) without the test policy (trident-test-selinux). -# -# It uses the same disk layout as 'base' but is intended to run on an image -# built WITHOUT trident-test-selinux installed. -# -# NOTE: The storm-trident test harness runs trident via SSH (unconfined_t), -# which requires the unconfined_run_to transition in trident-test-selinux. -# Until the test harness supports systemd-activated trident invocation, -# this config should be run on an image that includes the test SELinux policy. -# The value of this config is as a placeholder for future public-policy-only -# validation once the test infrastructure supports it. diff --git a/tests/e2e_tests/trident_configurations/selinux-public-only/trident-config.yaml b/tests/e2e_tests/trident_configurations/selinux-public-only/trident-config.yaml deleted file mode 100644 index 6c15a9dcc..000000000 --- a/tests/e2e_tests/trident_configurations/selinux-public-only/trident-config.yaml +++ /dev/null @@ -1,72 +0,0 @@ -image: - url: http://NETLAUNCH_HOST_ADDRESS/files/regular.cosi - sha384: ignored -storage: - disks: - - id: os - device: /dev/disk/by-path/pci-0000:00:1f.2-ata-2 - partitionTableType: gpt - partitions: - - id: root-a - type: root - size: 8G - - id: root-b - type: root - size: 8G - - id: esp - type: esp - size: 1G - - id: swap - type: swap - size: 2G - - id: home - type: home - size: 1G - - id: trident - type: linux-generic - size: 1G - - id: disk2 - device: /dev/disk/by-path/pci-0000:00:1f.2-ata-3 - partitionTableType: gpt - partitions: [] - abUpdate: - volumePairs: - - id: root - volumeAId: root-a - volumeBId: root-b - filesystems: - - deviceId: trident - source: new - mountPoint: /var/lib/trident - - deviceId: home - source: new - mountPoint: /home - - deviceId: esp - mountPoint: - path: /boot/efi - options: umask=0077 - - deviceId: root - mountPoint: / - swap: - - swap -scripts: - postConfigure: - - name: testing-privilege - runOn: - - clean-install - - ab-update - content: echo 'testing-user ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/testing-user -os: - selinux: - mode: enforcing - netplan: - version: 2 - ethernets: - vmeths: - match: - name: enp* - dhcp4: true - users: - - name: testing-user - sshPublicKeys: [] - sshMode: key-only From acca620bb3a9579bce61d65739fbcd96f7487962 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 14:21:47 -0700 Subject: [PATCH 08/59] refactor: use build-image.yml for SELinux test image builds Use the standard trident_images/build-image.yml template instead of directly calling trident-testimg-template.yml. Split into a separate BuildSELinuxTestImages stage for the image builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index ded369afe..461ca24c1 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -18,33 +18,37 @@ parameters: default: [] stages: - - stage: SELinuxUpdateValidation - displayName: SELinux Policy Update Validation + - stage: BuildSELinuxTestImages + displayName: Build SELinux Test Images dependsOn: - PrepareSSHKeys - GetTridentBinaries_rpms_amd64 - - BuildingTools - ${{ each stage in parameters.dependsOnStages }}: - ${{ stage }} jobs: - # Build the SELinux test images - - template: ../trident_images/trident-testimg-template.yml + - template: ../trident_images/build-image.yml parameters: - target: artifacts/trident-selinux-testimage.qcow2 label: selinux-base + makeTarget: artifacts/trident-selinux-testimage.qcow2 + baseimgType: core - - template: ../trident_images/trident-testimg-template.yml + - template: ../trident_images/build-image.yml parameters: - target: artifacts/trident-selinux-testimage-update.cosi label: selinux-update + makeTarget: artifacts/trident-selinux-testimage-update.cosi + baseimgType: core + - stage: SELinuxUpdateValidation + displayName: SELinux Policy Update Validation + dependsOn: + - BuildSELinuxTestImages + - BuildingTools + + jobs: # Run the SELinux update validation test - job: SELinuxUpdateTest displayName: SELinux Update Test - dependsOn: - - TridentTestImg_selinux_base - - TridentTestImg_selinux_update timeoutInMinutes: 30 pool: type: linux @@ -68,8 +72,8 @@ stages: # Download the built images from pipeline artifacts echo "Downloading SELinux test images..." - cp $(System.ArtifactsDirectory)/selinux-base/trident-selinux-testimage.qcow2 artifacts/ - cp $(System.ArtifactsDirectory)/selinux-update/trident-selinux-testimage-update.cosi artifacts/test-image/usrverity.cosi + cp $(System.ArtifactsDirectory)/image-selinux-base/trident-selinux-testimage.qcow2 artifacts/ + cp $(System.ArtifactsDirectory)/image-selinux-update/trident-selinux-testimage-update.cosi artifacts/test-image/usrverity.cosi workingDirectory: $(TRIDENT_SOURCE_DIR) displayName: "Download SELinux test images" From 5c29d89bd66c1e7d25246ccdbcc2817b299dbd88 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 14:32:20 -0700 Subject: [PATCH 09/59] fix: replace nonexistent download-tools.yml with actual artifact download Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 461ca24c1..634a4bbfc 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -64,7 +64,14 @@ stages: steps: - template: ../common_tasks/checkout_trident.yml - - template: ../testing_common/download-tools.yml + - task: DownloadPipelineArtifact@2 + displayName: "Download Go tools" + inputs: + buildType: current + artifactName: go-tools + targetPath: "$(TRIDENT_SOURCE_DIR)/bin" + - bash: chmod +x $(TRIDENT_SOURCE_DIR)/bin/* + displayName: "Make go tools executable" - bash: | set -eux From eded4b3d6dae6d836f474fd7a742efe4a92d7a8f Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 14:40:16 -0700 Subject: [PATCH 10/59] fix: add DownloadPipelineArtifact for SELinux test images The SELinux test images are built in a separate stage and need to be explicitly downloaded via DownloadPipelineArtifact@2 before use. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 634a4bbfc..851c76227 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -73,14 +73,24 @@ stages: - bash: chmod +x $(TRIDENT_SOURCE_DIR)/bin/* displayName: "Make go tools executable" + - task: DownloadPipelineArtifact@2 + displayName: "Download SELinux base image" + inputs: + buildType: current + artifactName: image-selinux-base + targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts" + + - task: DownloadPipelineArtifact@2 + displayName: "Download SELinux update image" + inputs: + buildType: current + artifactName: image-selinux-update + targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts/test-image" + - bash: | set -eux - mkdir -p artifacts/iso artifacts/test-image - - # Download the built images from pipeline artifacts - echo "Downloading SELinux test images..." - cp $(System.ArtifactsDirectory)/image-selinux-base/trident-selinux-testimage.qcow2 artifacts/ - cp $(System.ArtifactsDirectory)/image-selinux-update/trident-selinux-testimage-update.cosi artifacts/test-image/usrverity.cosi + ls -lh artifacts/ + ls -lh artifacts/test-image/ workingDirectory: $(TRIDENT_SOURCE_DIR) displayName: "Download SELinux test images" From e95020f5da8cf6d713c9fff10ae01136bda885b0 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 14:45:45 -0700 Subject: [PATCH 11/59] fix: download installer ISO and add stage dependency The SELinux test needs the trident-installer ISO for netlaunch. Added DownloadPipelineArtifact and TridentTestImg_trident_installer dependency. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 851c76227..8c5970fe4 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -44,6 +44,7 @@ stages: dependsOn: - BuildSELinuxTestImages - BuildingTools + - TridentTestImg_trident_installer jobs: # Run the SELinux update validation test @@ -87,6 +88,13 @@ stages: artifactName: image-selinux-update targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts/test-image" + - task: DownloadPipelineArtifact@2 + displayName: "Download installer ISO" + inputs: + buildType: current + artifactName: trident-installer + targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts/iso" + - bash: | set -eux ls -lh artifacts/ From dc1ce184c9f37cc9b5d6bbade910d450fb08008b Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 14:46:32 -0700 Subject: [PATCH 12/59] refactor: use download-test-images.yml for ISO and tools download Replace manual DownloadPipelineArtifact calls with the standard download-test-images.yml template, which handles ISO, Go tools, prepare-images, and chmod in one shot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 8c5970fe4..16dd22eb6 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -45,6 +45,7 @@ stages: - BuildSELinuxTestImages - BuildingTools - TridentTestImg_trident_installer + - TridentTestImg_trident_testimage jobs: # Run the SELinux update validation test @@ -65,15 +66,16 @@ stages: steps: - template: ../common_tasks/checkout_trident.yml - - task: DownloadPipelineArtifact@2 - displayName: "Download Go tools" - inputs: - buildType: current - artifactName: go-tools - targetPath: "$(TRIDENT_SOURCE_DIR)/bin" - - bash: chmod +x $(TRIDENT_SOURCE_DIR)/bin/* - displayName: "Make go tools executable" + # Download installer ISO, Go tools, and set up test images + - template: ../testing_common/download-test-images.yml + parameters: + installerISO: trident-installer + tridentTestImage: trident-testimage + tridentTestImageVerity: skip + tridentTestImageUsrVerity: skip + tridentSourceDirectory: $(TRIDENT_SOURCE_DIR) + # Download SELinux-specific test images (built in BuildSELinuxTestImages) - task: DownloadPipelineArtifact@2 displayName: "Download SELinux base image" inputs: @@ -88,13 +90,6 @@ stages: artifactName: image-selinux-update targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts/test-image" - - task: DownloadPipelineArtifact@2 - displayName: "Download installer ISO" - inputs: - buildType: current - artifactName: trident-installer - targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts/iso" - - bash: | set -eux ls -lh artifacts/ From c0dc4a36e16847a6f6e42932186e10d4c616f2c4 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 14:47:18 -0700 Subject: [PATCH 13/59] refactor: use explicit artifact downloads instead of download-test-images.yml Only download the 4 artifacts actually needed: Go tools (netlaunch, storm-trident, virtdeploy), installer ISO, SELinux base image, and SELinux update COSI. No unnecessary testimage downloads or prepare-images processing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 16dd22eb6..008455403 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -45,7 +45,6 @@ stages: - BuildSELinuxTestImages - BuildingTools - TridentTestImg_trident_installer - - TridentTestImg_trident_testimage jobs: # Run the SELinux update validation test @@ -66,16 +65,26 @@ stages: steps: - template: ../common_tasks/checkout_trident.yml - # Download installer ISO, Go tools, and set up test images - - template: ../testing_common/download-test-images.yml - parameters: - installerISO: trident-installer - tridentTestImage: trident-testimage - tridentTestImageVerity: skip - tridentTestImageUsrVerity: skip - tridentSourceDirectory: $(TRIDENT_SOURCE_DIR) + - task: DownloadPipelineArtifact@2 + displayName: "Download Go tools" + inputs: + buildType: current + artifactName: go-tools + patterns: | + netlaunch + storm-trident + virtdeploy + targetPath: "$(TRIDENT_SOURCE_DIR)/bin" + - bash: chmod +x $(TRIDENT_SOURCE_DIR)/bin/* + displayName: "Make tools executable" + + - task: DownloadPipelineArtifact@2 + displayName: "Download installer ISO" + inputs: + buildType: current + artifactName: trident-installer + targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts/iso" - # Download SELinux-specific test images (built in BuildSELinuxTestImages) - task: DownloadPipelineArtifact@2 displayName: "Download SELinux base image" inputs: From 8bfb258b4f6cabc2c89b6a5773b9a50250bb5e37 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 14:57:12 -0700 Subject: [PATCH 14/59] cleanup: remove updateimg.yaml, use single build-image for both COSIs build-image.yml produces *_0.cosi and *_1.cosi by default, so a separate update image yaml is unnecessary. Single build job now produces both base and update COSIs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 19 +-- tests/images/testimages.py | 8 - .../base/updateimg.yaml | 154 ------------------ 3 files changed, 3 insertions(+), 178 deletions(-) delete mode 100644 tests/images/trident-selinux-testimage/base/updateimg.yaml diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 008455403..3dffa92f6 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -29,16 +29,10 @@ stages: jobs: - template: ../trident_images/build-image.yml parameters: - label: selinux-base + label: selinux-testimage makeTarget: artifacts/trident-selinux-testimage.qcow2 baseimgType: core - - template: ../trident_images/build-image.yml - parameters: - label: selinux-update - makeTarget: artifacts/trident-selinux-testimage-update.cosi - baseimgType: core - - stage: SELinuxUpdateValidation displayName: SELinux Policy Update Validation dependsOn: @@ -86,17 +80,10 @@ stages: targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts/iso" - task: DownloadPipelineArtifact@2 - displayName: "Download SELinux base image" - inputs: - buildType: current - artifactName: image-selinux-base - targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts" - - - task: DownloadPipelineArtifact@2 - displayName: "Download SELinux update image" + displayName: "Download SELinux test images" inputs: buildType: current - artifactName: image-selinux-update + artifactName: image-selinux-testimage targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts/test-image" - bash: | diff --git a/tests/images/testimages.py b/tests/images/testimages.py index fc7dd6a37..eb34dc422 100755 --- a/tests/images/testimages.py +++ b/tests/images/testimages.py @@ -103,14 +103,6 @@ requires_ukify=True, ssh_key="../../trident-vm-testimage/base/files/id_rsa.pub", ), - ImageConfig( - "trident-selinux-testimage-update", - base_image=BaseImage.QEMU_GUEST, - config="trident-selinux-testimage", - config_file="base/updateimg.yaml", - requires_ukify=True, - ssh_key="../../trident-vm-testimage/base/files/id_rsa.pub", - ), ImageConfig( "trident-vm-grub-verity-azure-testimage", base_image=BaseImage.CORE_SELINUX, diff --git a/tests/images/trident-selinux-testimage/base/updateimg.yaml b/tests/images/trident-selinux-testimage/base/updateimg.yaml deleted file mode 100644 index 207fbbccb..000000000 --- a/tests/images/trident-selinux-testimage/base/updateimg.yaml +++ /dev/null @@ -1,154 +0,0 @@ -# SELinux validation update image. -# Paired with baseimg.yaml — uses enforcing SELinux with public policy only. -storage: - bootType: efi - - disks: - - partitionTableType: gpt - maxSize: 7G - partitions: - - id: esp - type: esp - size: 8M - - - id: boot - size: 256M - - - id: root - size: 4G - - - id: root-hash - size: 128M - - - id: var - size: 1G - - - id: trident-overlay - size: 32M - - - id: srv - size: 1G - - - id: home - size: 32M - - verity: - - id: rootverity - name: root - dataDeviceId: root - hashDeviceId: root-hash - dataDeviceMountIdType: uuid - hashDeviceMountIdType: uuid - - filesystems: - - deviceId: esp - type: fat32 - mountPoint: - options: umask=0077 - path: /boot/efi - - - deviceId: boot - type: ext4 - mountPoint: - path: /boot - - - deviceId: rootverity - type: ext4 - mountPoint: - path: / - options: defaults,ro - - - deviceId: var - type: ext4 - mountPoint: - path: /var - - - deviceId: trident-overlay - type: ext4 - mountPoint: - path: /var/lib/trident-overlay - - - deviceId: srv - type: ext4 - mountPoint: - path: /srv - - - deviceId: home - type: ext4 - mountPoint: - path: /home - -os: - bootloader: - resetType: hard-reset - hostname: trident-selinux-testimg - - selinux: - mode: enforcing - - kernelCommandLine: - extraCommandLine: - - console=tty0 - - console=tty1 - - console=ttyS0 - - rd.debug - - loglevel=6 - - log_buf_len=1M - - systemd.journald.forward_to_console=1 - - packages: - install: - - curl - - device-mapper - - dnf - - dracut-overlayfs - - efibootmgr - - grub2-efi-binary-noprefix - - iproute - - iptables - - jq - - kexec-tools - - lsof - - lvm2 - - netplan - - openssh-server - - selinux-policy - - systemd-udev - - trident-service - # NOTE: trident-test-selinux is intentionally NOT installed. - - veritysetup - - vim - - WALinuxAgent - remove: - - grub2-efi-binary - - additionalFiles: - - source: ../../trident-vm-testimage/base/files/etc-mount.service - destination: /etc/systemd/system/etc-mount.service - - source: ../../trident-vm-testimage/base/files/etc-mount.sh - destination: /usr/local/bin/etc-mount.sh - - source: ../../trident-vm-testimage/base/files/sudoers-wheel - destination: /etc/sudoers.d/wheel - - source: ../../trident-vm-testimage/base/files/99-dhcp-eth0.network - destination: /etc/systemd/network/99-dhcp-eth0.network - - source: ../../trident-vm-testimage/base/files/use-grpc-client-commit.conf - destination: /etc/systemd/system/trident.service.d/override.conf - - services: - enable: - - etc-mount - - kdump - - trident - - tridentd.socket - - users: - - name: testuser - secondaryGroups: - - wheel - -scripts: - postCustomization: - - path: ../../trident-vm-testimage/base/scripts/post-install.sh - - path: ../../trident-vm-testimage/base/scripts/ssh-move-host-keys.sh - - path: ../../trident-vm-testimage/base/scripts/update-os-release.sh - - path: ../../trident-vm-testimage/base/scripts/duid-type-to-link-layer.sh From a5ae5a2ab45f791cee3b7397b082d78add085dba Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 15:03:56 -0700 Subject: [PATCH 15/59] fix: rename COSIs to usrverity.cosi/usrverity_v2.cosi for usr-verity config The SELinux test uses tests/e2e_tests/trident_configurations/usr-verity/ trident-config.yaml which expects usrverity.cosi. Rename the build artifacts (*_0.cosi -> usrverity.cosi, *_1.cosi -> usrverity_v2.cosi). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../testing_selinux/selinux-update-testing.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 3dffa92f6..cd013abe9 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -88,10 +88,15 @@ stages: - bash: | set -eux - ls -lh artifacts/ - ls -lh artifacts/test-image/ + cd artifacts/test-image + + # Rename COSIs to match what usr-verity trident-config.yaml expects + ls -lh + mv *_0.cosi usrverity.cosi + mv *_1.cosi usrverity_v2.cosi + ls -lh workingDirectory: $(TRIDENT_SOURCE_DIR) - displayName: "Download SELinux test images" + displayName: "Rename COSIs for usr-verity config" - bash: | set -eux @@ -109,7 +114,7 @@ stages: TRIDENT_CONFIG="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/trident_configurations/usr-verity/trident-config.yaml" SIGNING_CERT="" - CA_CERT_PATH="$(System.ArtifactsDirectory)/selinux-base/ca_cert.pem" + CA_CERT_PATH="$(TRIDENT_SOURCE_DIR)/artifacts/test-image/ca_cert.pem" if [ -f "$CA_CERT_PATH" ]; then SIGNING_CERT="--signing-cert $CA_CERT_PATH" fi From eca9e117ae92ac0bf570ba043c759fb8a7ac94d4 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 15:41:00 -0700 Subject: [PATCH 16/59] fix: use qemu_guest baseimgType for SELinux test image The SELinux test image uses BaseImage.QEMU_GUEST in testimages.py, so the pipeline needs to download the matching qemu_guest base image. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../templates/stages/testing_selinux/selinux-update-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index cd013abe9..a77944df9 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -31,7 +31,7 @@ stages: parameters: label: selinux-testimage makeTarget: artifacts/trident-selinux-testimage.qcow2 - baseimgType: core + baseimgType: qemu_guest - stage: SELinuxUpdateValidation displayName: SELinux Policy Update Validation From 8fe9a1d7abc3eb773850f11f5e8fc4ff473e1360 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 16:37:48 -0700 Subject: [PATCH 17/59] fix: pass micBuildType, micVersion, useStagedSshKeys to build-image Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .pipelines/templates/e2e-template.yml | 3 +++ .../testing_selinux/selinux-update-testing.yml | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/.pipelines/templates/e2e-template.yml b/.pipelines/templates/e2e-template.yml index c49c67456..34786380f 100644 --- a/.pipelines/templates/e2e-template.yml +++ b/.pipelines/templates/e2e-template.yml @@ -423,6 +423,9 @@ stages: # SELinux policy validation — tests update with public policy only - template: stages/testing_selinux/selinux-update-testing.yml + parameters: + micBuildType: ${{ parameters.micBuildType }} + micVersion: ${{ parameters.micVersion }} # TESTING stages for AZL-VALIDATION - ${{ if eq(parameters.stageType, 'azl-validation') }}: diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index a77944df9..c6ec1f04c 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -17,6 +17,20 @@ parameters: type: object default: [] + - name: micBuildType + displayName: MIC Build Type + type: string + values: + - dev + - preview + - release + default: release + + - name: micVersion + displayName: MIC Version + type: string + default: "*.*.*" + stages: - stage: BuildSELinuxTestImages displayName: Build SELinux Test Images @@ -32,6 +46,9 @@ stages: label: selinux-testimage makeTarget: artifacts/trident-selinux-testimage.qcow2 baseimgType: qemu_guest + micBuildType: ${{ parameters.micBuildType }} + micVersion: ${{ parameters.micVersion }} + useStagedSshKeys: true - stage: SELinuxUpdateValidation displayName: SELinux Policy Update Validation From 4801c9a4cdf07212ffe05a8dba96b22be752b06c Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 16:43:11 -0700 Subject: [PATCH 18/59] fix: build COSI not qcow2 for SELinux test image Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../templates/stages/testing_selinux/selinux-update-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index c6ec1f04c..77d3d45f0 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -44,7 +44,7 @@ stages: - template: ../trident_images/build-image.yml parameters: label: selinux-testimage - makeTarget: artifacts/trident-selinux-testimage.qcow2 + makeTarget: artifacts/trident-selinux-testimage.cosi baseimgType: qemu_guest micBuildType: ${{ parameters.micBuildType }} micVersion: ${{ parameters.micVersion }} From ee8b8f33eebd27738687f4560ecbe3f2b2280484 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 17:34:54 -0700 Subject: [PATCH 19/59] refactor: copy referenced files into trident-selinux-testimage, use local paths Copy files and scripts from trident-vm-testimage into the SELinux test image directory and update baseimg.yaml to use local paths instead of relative references to sibling directories. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../base/baseimg.yaml | 16 ++++----- .../base/files/99-dhcp-eth0.network | 6 ++++ .../base/files/sudoers-wheel | 1 + .../base/files/trident-update@.service | 12 +++++++ .../base/scripts/duid-type-to-link-layer.sh | 1 + .../base/scripts/post-install.sh | 2 ++ .../scripts/prepare-update-config-verity.sh | 36 +++++++++++++++++++ .../base/scripts/update-host-status.sh | 1 + 8 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 tests/images/trident-selinux-testimage/base/files/99-dhcp-eth0.network create mode 100644 tests/images/trident-selinux-testimage/base/files/sudoers-wheel create mode 100644 tests/images/trident-selinux-testimage/base/files/trident-update@.service create mode 100644 tests/images/trident-selinux-testimage/base/scripts/duid-type-to-link-layer.sh create mode 100644 tests/images/trident-selinux-testimage/base/scripts/post-install.sh create mode 100644 tests/images/trident-selinux-testimage/base/scripts/prepare-update-config-verity.sh create mode 100644 tests/images/trident-selinux-testimage/base/scripts/update-host-status.sh diff --git a/tests/images/trident-selinux-testimage/base/baseimg.yaml b/tests/images/trident-selinux-testimage/base/baseimg.yaml index 4cdc8b716..2c420670e 100644 --- a/tests/images/trident-selinux-testimage/base/baseimg.yaml +++ b/tests/images/trident-selinux-testimage/base/baseimg.yaml @@ -147,13 +147,13 @@ os: - grub2-efi-binary additionalFiles: - - source: ../../trident-vm-testimage/base/files/99-dhcp-eth0.network + - source: files/99-dhcp-eth0.network destination: /etc/systemd/network/99-dhcp-eth0.network - - source: ../../trident-vm-testimage/base/files/sudoers-wheel + - source: files/sudoers-wheel destination: /etc/sudoers.d/wheel # Trident update service template — runs updates via systemd domain # transition (init_t -> trident_t), exercising the production SELinux path. - - source: ../../../../packaging/systemd/trident-update@.service + - source: files/trident-update@.service destination: /usr/lib/systemd/system/trident-update@.service services: @@ -165,18 +165,18 @@ os: users: - name: testuser sshPublicKeyPaths: - - ../../trident-vm-testimage/base/files/id_rsa.pub + - files/id_rsa.pub secondaryGroups: - wheel scripts: postCustomization: - - path: ../../trident-vm-testimage/base/scripts/post-install.sh - - path: ../../trident-vm-testimage/base/scripts/update-host-status.sh - - path: ../../trident-vm-testimage/base/scripts/prepare-update-config-verity.sh + - path: scripts/post-install.sh + - path: scripts/update-host-status.sh + - path: scripts/prepare-update-config-verity.sh arguments: - uki - - path: ../../trident-vm-testimage/base/scripts/duid-type-to-link-layer.sh + - path: scripts/duid-type-to-link-layer.sh previewFeatures: - uki diff --git a/tests/images/trident-selinux-testimage/base/files/99-dhcp-eth0.network b/tests/images/trident-selinux-testimage/base/files/99-dhcp-eth0.network new file mode 100644 index 000000000..5cef9e24f --- /dev/null +++ b/tests/images/trident-selinux-testimage/base/files/99-dhcp-eth0.network @@ -0,0 +1,6 @@ +[Match] +Name=eth0 + +[Network] +DHCP=yes +IPv6AcceptRA=no \ No newline at end of file diff --git a/tests/images/trident-selinux-testimage/base/files/sudoers-wheel b/tests/images/trident-selinux-testimage/base/files/sudoers-wheel new file mode 100644 index 000000000..c8b362960 --- /dev/null +++ b/tests/images/trident-selinux-testimage/base/files/sudoers-wheel @@ -0,0 +1 @@ +%wheel ALL=(ALL:ALL) NOPASSWD: ALL \ No newline at end of file diff --git a/tests/images/trident-selinux-testimage/base/files/trident-update@.service b/tests/images/trident-selinux-testimage/base/files/trident-update@.service new file mode 100644 index 000000000..b623f7f7a --- /dev/null +++ b/tests/images/trident-selinux-testimage/base/files/trident-update@.service @@ -0,0 +1,12 @@ +[Unit] +Description=Trident Update (%i) +After=network.target network-online.target tridentd.socket + +[Service] +Type=oneshot +EnvironmentFile=/var/lib/trident/update-env +ExecStart=trident grpc-client update -v ${TRIDENT_VERBOSITY} ${UPDATE_CONFIG} --allowed-operations %i +TimeoutStartSec=600 + +[Install] +WantedBy=multi-user.target diff --git a/tests/images/trident-selinux-testimage/base/scripts/duid-type-to-link-layer.sh b/tests/images/trident-selinux-testimage/base/scripts/duid-type-to-link-layer.sh new file mode 100644 index 000000000..5c35e32cf --- /dev/null +++ b/tests/images/trident-selinux-testimage/base/scripts/duid-type-to-link-layer.sh @@ -0,0 +1 @@ +sed -i 's/#DUIDType=vendor/DUIDType=link-layer/' /etc/systemd/networkd.conf \ No newline at end of file diff --git a/tests/images/trident-selinux-testimage/base/scripts/post-install.sh b/tests/images/trident-selinux-testimage/base/scripts/post-install.sh new file mode 100644 index 000000000..b960507cd --- /dev/null +++ b/tests/images/trident-selinux-testimage/base/scripts/post-install.sh @@ -0,0 +1,2 @@ +# Add the necessary directories for the audit logs so that auditd can start +mkdir -p /var/log/audit \ No newline at end of file diff --git a/tests/images/trident-selinux-testimage/base/scripts/prepare-update-config-verity.sh b/tests/images/trident-selinux-testimage/base/scripts/prepare-update-config-verity.sh new file mode 100644 index 000000000..600151fdd --- /dev/null +++ b/tests/images/trident-selinux-testimage/base/scripts/prepare-update-config-verity.sh @@ -0,0 +1,36 @@ +CONFIG_PATH=/var/lib/trident/update-config.yaml +DOWNLOAD_URL_PREFIX="http://192.168.122.1:8000" + +cat < $CONFIG_PATH +image: + url: $DOWNLOAD_URL_PREFIX/verity.cosi + sha384: ignored +EOF + +INTERFACE_MASK='enp*' +if [ "$1" == "eth0" ]; then + INTERFACE_MASK="$1" +fi + +if [ "$1" != "uki" ]; then + cat <> $CONFIG_PATH +scripts: + postConfigure: + - name: rw-overlay + runOn: [all] + content: | + mkdir -p /var/lib/trident-overlay/etc-rw/upper && mkdir -p /var/lib/trident-overlay/etc-rw/work +EOF +fi + +cat <> $CONFIG_PATH +internalParams: + allowUnusedFilesystems: true +EOF + +if [ "$1" == "uki" ]; then + cat <> $CONFIG_PATH + uki: true + disableGrubNoprefixCheck: true +EOF +fi diff --git a/tests/images/trident-selinux-testimage/base/scripts/update-host-status.sh b/tests/images/trident-selinux-testimage/base/scripts/update-host-status.sh new file mode 100644 index 000000000..4a69a0221 --- /dev/null +++ b/tests/images/trident-selinux-testimage/base/scripts/update-host-status.sh @@ -0,0 +1 @@ +trident offline-initialize From f47e3943ff61eaafa5d752c57f817f4c6e93859b Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 17:35:25 -0700 Subject: [PATCH 20/59] rename: trident-selinux-testimage -> trident-testimage/selinux Rename directory structure: tests/images/trident-selinux-testimage/base/ -> tests/images/trident-testimage/selinux/ Update testimages.py config and ssh_key paths to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/images/testimages.py | 6 +++--- .../base => trident-testimage/selinux}/baseimg.yaml | 0 .../selinux}/files/99-dhcp-eth0.network | 0 .../base => trident-testimage/selinux}/files/sudoers-wheel | 0 .../selinux}/files/trident-update@.service | 0 .../selinux}/scripts/duid-type-to-link-layer.sh | 0 .../selinux}/scripts/post-install.sh | 0 .../selinux}/scripts/prepare-update-config-verity.sh | 0 .../selinux}/scripts/update-host-status.sh | 0 9 files changed, 3 insertions(+), 3 deletions(-) rename tests/images/{trident-selinux-testimage/base => trident-testimage/selinux}/baseimg.yaml (100%) rename tests/images/{trident-selinux-testimage/base => trident-testimage/selinux}/files/99-dhcp-eth0.network (100%) rename tests/images/{trident-selinux-testimage/base => trident-testimage/selinux}/files/sudoers-wheel (100%) rename tests/images/{trident-selinux-testimage/base => trident-testimage/selinux}/files/trident-update@.service (100%) rename tests/images/{trident-selinux-testimage/base => trident-testimage/selinux}/scripts/duid-type-to-link-layer.sh (100%) rename tests/images/{trident-selinux-testimage/base => trident-testimage/selinux}/scripts/post-install.sh (100%) rename tests/images/{trident-selinux-testimage/base => trident-testimage/selinux}/scripts/prepare-update-config-verity.sh (100%) rename tests/images/{trident-selinux-testimage/base => trident-testimage/selinux}/scripts/update-host-status.sh (100%) diff --git a/tests/images/testimages.py b/tests/images/testimages.py index eb34dc422..8bd131cb9 100755 --- a/tests/images/testimages.py +++ b/tests/images/testimages.py @@ -98,10 +98,10 @@ ImageConfig( "trident-selinux-testimage", base_image=BaseImage.QEMU_GUEST, - config="trident-selinux-testimage", - config_file="base/baseimg.yaml", + config="trident-testimage", + config_file="selinux/baseimg.yaml", requires_ukify=True, - ssh_key="../../trident-vm-testimage/base/files/id_rsa.pub", + ssh_key="selinux/files/id_rsa.pub", ), ImageConfig( "trident-vm-grub-verity-azure-testimage", diff --git a/tests/images/trident-selinux-testimage/base/baseimg.yaml b/tests/images/trident-testimage/selinux/baseimg.yaml similarity index 100% rename from tests/images/trident-selinux-testimage/base/baseimg.yaml rename to tests/images/trident-testimage/selinux/baseimg.yaml diff --git a/tests/images/trident-selinux-testimage/base/files/99-dhcp-eth0.network b/tests/images/trident-testimage/selinux/files/99-dhcp-eth0.network similarity index 100% rename from tests/images/trident-selinux-testimage/base/files/99-dhcp-eth0.network rename to tests/images/trident-testimage/selinux/files/99-dhcp-eth0.network diff --git a/tests/images/trident-selinux-testimage/base/files/sudoers-wheel b/tests/images/trident-testimage/selinux/files/sudoers-wheel similarity index 100% rename from tests/images/trident-selinux-testimage/base/files/sudoers-wheel rename to tests/images/trident-testimage/selinux/files/sudoers-wheel diff --git a/tests/images/trident-selinux-testimage/base/files/trident-update@.service b/tests/images/trident-testimage/selinux/files/trident-update@.service similarity index 100% rename from tests/images/trident-selinux-testimage/base/files/trident-update@.service rename to tests/images/trident-testimage/selinux/files/trident-update@.service diff --git a/tests/images/trident-selinux-testimage/base/scripts/duid-type-to-link-layer.sh b/tests/images/trident-testimage/selinux/scripts/duid-type-to-link-layer.sh similarity index 100% rename from tests/images/trident-selinux-testimage/base/scripts/duid-type-to-link-layer.sh rename to tests/images/trident-testimage/selinux/scripts/duid-type-to-link-layer.sh diff --git a/tests/images/trident-selinux-testimage/base/scripts/post-install.sh b/tests/images/trident-testimage/selinux/scripts/post-install.sh similarity index 100% rename from tests/images/trident-selinux-testimage/base/scripts/post-install.sh rename to tests/images/trident-testimage/selinux/scripts/post-install.sh diff --git a/tests/images/trident-selinux-testimage/base/scripts/prepare-update-config-verity.sh b/tests/images/trident-testimage/selinux/scripts/prepare-update-config-verity.sh similarity index 100% rename from tests/images/trident-selinux-testimage/base/scripts/prepare-update-config-verity.sh rename to tests/images/trident-testimage/selinux/scripts/prepare-update-config-verity.sh diff --git a/tests/images/trident-selinux-testimage/base/scripts/update-host-status.sh b/tests/images/trident-testimage/selinux/scripts/update-host-status.sh similarity index 100% rename from tests/images/trident-selinux-testimage/base/scripts/update-host-status.sh rename to tests/images/trident-testimage/selinux/scripts/update-host-status.sh From 1d359c58e333f059c45d06571576b3abe6930f42 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 17:36:30 -0700 Subject: [PATCH 21/59] rename: trident-testimage/selinux -> trident-testimage/base Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/images/testimages.py | 4 ++-- tests/images/trident-testimage/{selinux => base}/baseimg.yaml | 0 .../{selinux => base}/files/99-dhcp-eth0.network | 0 .../trident-testimage/{selinux => base}/files/sudoers-wheel | 0 .../{selinux => base}/files/trident-update@.service | 0 .../{selinux => base}/scripts/duid-type-to-link-layer.sh | 0 .../{selinux => base}/scripts/post-install.sh | 0 .../{selinux => base}/scripts/prepare-update-config-verity.sh | 0 .../{selinux => base}/scripts/update-host-status.sh | 0 9 files changed, 2 insertions(+), 2 deletions(-) rename tests/images/trident-testimage/{selinux => base}/baseimg.yaml (100%) rename tests/images/trident-testimage/{selinux => base}/files/99-dhcp-eth0.network (100%) rename tests/images/trident-testimage/{selinux => base}/files/sudoers-wheel (100%) rename tests/images/trident-testimage/{selinux => base}/files/trident-update@.service (100%) rename tests/images/trident-testimage/{selinux => base}/scripts/duid-type-to-link-layer.sh (100%) rename tests/images/trident-testimage/{selinux => base}/scripts/post-install.sh (100%) rename tests/images/trident-testimage/{selinux => base}/scripts/prepare-update-config-verity.sh (100%) rename tests/images/trident-testimage/{selinux => base}/scripts/update-host-status.sh (100%) diff --git a/tests/images/testimages.py b/tests/images/testimages.py index 8bd131cb9..10255ea8f 100755 --- a/tests/images/testimages.py +++ b/tests/images/testimages.py @@ -99,9 +99,9 @@ "trident-selinux-testimage", base_image=BaseImage.QEMU_GUEST, config="trident-testimage", - config_file="selinux/baseimg.yaml", + config_file="base/baseimg.yaml", requires_ukify=True, - ssh_key="selinux/files/id_rsa.pub", + ssh_key="base/files/id_rsa.pub", ), ImageConfig( "trident-vm-grub-verity-azure-testimage", diff --git a/tests/images/trident-testimage/selinux/baseimg.yaml b/tests/images/trident-testimage/base/baseimg.yaml similarity index 100% rename from tests/images/trident-testimage/selinux/baseimg.yaml rename to tests/images/trident-testimage/base/baseimg.yaml diff --git a/tests/images/trident-testimage/selinux/files/99-dhcp-eth0.network b/tests/images/trident-testimage/base/files/99-dhcp-eth0.network similarity index 100% rename from tests/images/trident-testimage/selinux/files/99-dhcp-eth0.network rename to tests/images/trident-testimage/base/files/99-dhcp-eth0.network diff --git a/tests/images/trident-testimage/selinux/files/sudoers-wheel b/tests/images/trident-testimage/base/files/sudoers-wheel similarity index 100% rename from tests/images/trident-testimage/selinux/files/sudoers-wheel rename to tests/images/trident-testimage/base/files/sudoers-wheel diff --git a/tests/images/trident-testimage/selinux/files/trident-update@.service b/tests/images/trident-testimage/base/files/trident-update@.service similarity index 100% rename from tests/images/trident-testimage/selinux/files/trident-update@.service rename to tests/images/trident-testimage/base/files/trident-update@.service diff --git a/tests/images/trident-testimage/selinux/scripts/duid-type-to-link-layer.sh b/tests/images/trident-testimage/base/scripts/duid-type-to-link-layer.sh similarity index 100% rename from tests/images/trident-testimage/selinux/scripts/duid-type-to-link-layer.sh rename to tests/images/trident-testimage/base/scripts/duid-type-to-link-layer.sh diff --git a/tests/images/trident-testimage/selinux/scripts/post-install.sh b/tests/images/trident-testimage/base/scripts/post-install.sh similarity index 100% rename from tests/images/trident-testimage/selinux/scripts/post-install.sh rename to tests/images/trident-testimage/base/scripts/post-install.sh diff --git a/tests/images/trident-testimage/selinux/scripts/prepare-update-config-verity.sh b/tests/images/trident-testimage/base/scripts/prepare-update-config-verity.sh similarity index 100% rename from tests/images/trident-testimage/selinux/scripts/prepare-update-config-verity.sh rename to tests/images/trident-testimage/base/scripts/prepare-update-config-verity.sh diff --git a/tests/images/trident-testimage/selinux/scripts/update-host-status.sh b/tests/images/trident-testimage/base/scripts/update-host-status.sh similarity index 100% rename from tests/images/trident-testimage/selinux/scripts/update-host-status.sh rename to tests/images/trident-testimage/base/scripts/update-host-status.sh From e53e12eebe5eb684bf8ece656693dbac061e118e Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 17:38:28 -0700 Subject: [PATCH 22/59] rename: baseimg.yaml -> baseimg-selinux.yaml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/images/testimages.py | 2 +- .../base/{baseimg.yaml => baseimg-selinux.yaml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/images/trident-testimage/base/{baseimg.yaml => baseimg-selinux.yaml} (100%) diff --git a/tests/images/testimages.py b/tests/images/testimages.py index 10255ea8f..41c68502e 100755 --- a/tests/images/testimages.py +++ b/tests/images/testimages.py @@ -99,7 +99,7 @@ "trident-selinux-testimage", base_image=BaseImage.QEMU_GUEST, config="trident-testimage", - config_file="base/baseimg.yaml", + config_file="base/baseimg-selinux.yaml", requires_ukify=True, ssh_key="base/files/id_rsa.pub", ), diff --git a/tests/images/trident-testimage/base/baseimg.yaml b/tests/images/trident-testimage/base/baseimg-selinux.yaml similarity index 100% rename from tests/images/trident-testimage/base/baseimg.yaml rename to tests/images/trident-testimage/base/baseimg-selinux.yaml From 1cac1b3dd05da6e736257d56e75826a9410d6a15 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 17:48:46 -0700 Subject: [PATCH 23/59] cleanup: remove id_rsa.pub references from SELinux test image Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/images/testimages.py | 1 - tests/images/trident-testimage/base/baseimg-selinux.yaml | 2 -- 2 files changed, 3 deletions(-) diff --git a/tests/images/testimages.py b/tests/images/testimages.py index 41c68502e..3d4220849 100755 --- a/tests/images/testimages.py +++ b/tests/images/testimages.py @@ -101,7 +101,6 @@ config="trident-testimage", config_file="base/baseimg-selinux.yaml", requires_ukify=True, - ssh_key="base/files/id_rsa.pub", ), ImageConfig( "trident-vm-grub-verity-azure-testimage", diff --git a/tests/images/trident-testimage/base/baseimg-selinux.yaml b/tests/images/trident-testimage/base/baseimg-selinux.yaml index 2c420670e..3b54ab257 100644 --- a/tests/images/trident-testimage/base/baseimg-selinux.yaml +++ b/tests/images/trident-testimage/base/baseimg-selinux.yaml @@ -164,8 +164,6 @@ os: users: - name: testuser - sshPublicKeyPaths: - - files/id_rsa.pub secondaryGroups: - wheel From 8b049d4df3690d5e8c4394c2071b438a2b57c749 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 18:17:00 -0700 Subject: [PATCH 24/59] feat: add optional --clones flag to COSI/ISO/VHDX build target Pass --clones NUM_CLONES to testimages.py when NUM_CLONES is defined, e.g. make artifacts/trident-selinux-testimage.cosi NUM_CLONES=2 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a7d72c274..cf14fa478 100644 --- a/Makefile +++ b/Makefile @@ -954,7 +954,8 @@ artifacts/%.cosi artifacts/%.iso artifacts/%.vhdx: $$(shell ./tests/images/testi $* \ --output-dir ./artifacts \ $(if $(strip $(MIC_CONTAINER_IMAGE)),--container $(MIC_CONTAINER_IMAGE)) \ - $(if $(strip $(MIC_ARCHITECTURE)),--image-architecture $(MIC_ARCHITECTURE)) + $(if $(strip $(MIC_ARCHITECTURE)),--image-architecture $(MIC_ARCHITECTURE)) \ + $(if $(strip $(NUM_CLONES)),--clones $(NUM_CLONES)) MIC_CONTAINER_IMAGE ?= $(shell ./tests/images/testimages.py show-artifact customizer-container-full) artifacts/trident-functest.qcow2: $$(shell ./tests/images/testimages.py dependencies $$(basename $$(notdir $$@))) From 65f5c7fe50616119fde3d67f7d781debfd14c1bc Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 18:29:01 -0700 Subject: [PATCH 25/59] feat: add numClones parameter to build-image pipeline Thread numClones through build-image.yml -> trident-testimg-template.yml -> make NUM_CLONES. SELinux test stage passes numClones=2 to get both *_0.cosi and *_1.cosi for base and update images. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 1 + .../templates/stages/trident_images/build-image.yml | 6 ++++++ .../stages/trident_images/trident-testimg-template.yml | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 77d3d45f0..3ecbfe561 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -49,6 +49,7 @@ stages: micBuildType: ${{ parameters.micBuildType }} micVersion: ${{ parameters.micVersion }} useStagedSshKeys: true + numClones: "2" - stage: SELinuxUpdateValidation displayName: SELinux Policy Update Validation diff --git a/.pipelines/templates/stages/trident_images/build-image.yml b/.pipelines/templates/stages/trident_images/build-image.yml index 6f70dafdc..92db5713a 100644 --- a/.pipelines/templates/stages/trident_images/build-image.yml +++ b/.pipelines/templates/stages/trident_images/build-image.yml @@ -73,6 +73,11 @@ parameters: type: number default: 20 + - name: numClones + displayName: "Number of image clones to produce" + type: string + default: "" + jobs: - job: PrepareImage_${{ replace(parameters.label, '-', '_') }} displayName: Prepare Image ${{ parameters.label }} @@ -142,3 +147,4 @@ jobs: - ${{ parameters.baseimgType }} useStagedSshKeys: ${{ parameters.useStagedSshKeys }} downloadTrident: ${{ parameters.downloadTrident }} + numClones: ${{ parameters.numClones }} diff --git a/.pipelines/templates/stages/trident_images/trident-testimg-template.yml b/.pipelines/templates/stages/trident_images/trident-testimg-template.yml index 2660aba09..e411d8d05 100644 --- a/.pipelines/templates/stages/trident_images/trident-testimg-template.yml +++ b/.pipelines/templates/stages/trident_images/trident-testimg-template.yml @@ -108,6 +108,10 @@ parameters: type: boolean default: false + - name: numClones + type: string + default: "" + steps: - template: ../common_tasks/avoid-pypi-usage.yml @@ -281,6 +285,10 @@ steps: export MIC_ARCHITECTURE="linux/${{ parameters.micArchitecture }}" fi + if [[ -n "${{ parameters.numClones }}" ]]; then + export NUM_CLONES="${{ parameters.numClones }}" + fi + # Compress the full image & delete the uncompressed image make ${{ parameters.target }} workingDirectory: ${{ parameters.tridentSourceDirectory }} From 11d074e9edeefc4b6de43b7b97fbb80e4419d0ae Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 18:57:56 -0700 Subject: [PATCH 26/59] fix: handle clone artifacts in output directory copy When numClones is used, the make target is e.g. artifacts/foo.cosi but the generated files are artifacts/foo_0.cosi, foo_1.cosi, etc. Glob on the base name to capture all clones, falling back to the exact target name for non-clone builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../trident_images/trident-testimg-template.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/stages/trident_images/trident-testimg-template.yml b/.pipelines/templates/stages/trident_images/trident-testimg-template.yml index e411d8d05..4a7899899 100644 --- a/.pipelines/templates/stages/trident_images/trident-testimg-template.yml +++ b/.pipelines/templates/stages/trident_images/trident-testimg-template.yml @@ -302,8 +302,18 @@ steps: if [ -d "build/${{ parameters.target }}" ]; then sudo mv -v build/${{ parameters.target }}/* "${{ parameters.outputDirectory }}/" else - # Everything else is a file - sudo mv -v "${{ parameters.target }}" "${{ parameters.outputDirectory }}/" + # When clones are produced, the target is e.g. artifacts/foo.cosi but + # the generated files are artifacts/foo_0.cosi, artifacts/foo_1.cosi, etc. + # Use a glob on the base name to capture all clones. + target="${{ parameters.target }}" + base="${target%.*}" + ext="${target##*.}" + clones=( ${base}_*.${ext} ) + if [ -e "${clones[0]}" ]; then + sudo mv -v "${base}"_*.${ext} "${{ parameters.outputDirectory }}/" + else + sudo mv -v "${{ parameters.target }}" "${{ parameters.outputDirectory }}/" + fi fi workingDirectory: ${{ parameters.tridentSourceDirectory }} displayName: "Copy artifacts to output directory" From 5f3742836188bfd97a80f9874541d1d1352b1ba6 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 19:21:09 -0700 Subject: [PATCH 27/59] fix: use netlaunch-prep.yml for libvirt/QEMU setup Reuse the standard netlaunch-prep.yml template for installing QEMU, libvirt, virt-firmware, and configuring libvirt access. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../templates/stages/testing_selinux/selinux-update-testing.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 3ecbfe561..86212d912 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -116,6 +116,8 @@ stages: workingDirectory: $(TRIDENT_SOURCE_DIR) displayName: "Rename COSIs for usr-verity config" + - template: ../testing_vm/netlaunch-prep.yml + - bash: | set -eux From 1b878024da8abef3e3f385aeef24746b8e49c1a4 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 19:24:43 -0700 Subject: [PATCH 28/59] fix: call trident-prep.yml to edit host config and set up SSH key Runs edit_host_config.py on the usr-verity trident-config.yaml and sets up the SSH key permissions before VM creation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 86212d912..42dc466ab 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -118,6 +118,13 @@ stages: - template: ../testing_vm/netlaunch-prep.yml + - template: ../testing_common/trident-prep.yml + parameters: + tridentSourceDirectory: $(TRIDENT_SOURCE_DIR) + tridentConfigPath: $(TRIDENT_SOURCE_DIR)/tests/e2e_tests/trident_configurations/usr-verity + runtimeEnv: host + config: usr-verity + - bash: | set -eux From 2a092d0da9778166a81d3976b952f2667aa914c6 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 19:52:39 -0700 Subject: [PATCH 29/59] refactor: rebase baseimg-selinux.yaml on trident-verity-testimage/usr/host.yaml Align the SELinux test image with the upstream test-images definition. Simpler storage layout (no A/B partitions), includes output artifacts config for UKI signing, and matches the package set used by the verity testimage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../base/baseimg-selinux.yaml | 160 +++++++----------- .../base/files/99-dhcp-eth0.network | 6 - .../base/files/dracut-nohostonly.conf | 1 + .../base/files/use-grpc-client-commit.conf | 5 + .../base/scripts/duid-type-to-link-layer.sh | 1 - .../base/scripts/post-install.sh | 2 - .../scripts/prepare-update-config-verity.sh | 36 ---- .../base/scripts/update-host-status.sh | 1 - 8 files changed, 64 insertions(+), 148 deletions(-) delete mode 100644 tests/images/trident-testimage/base/files/99-dhcp-eth0.network create mode 100644 tests/images/trident-testimage/base/files/dracut-nohostonly.conf create mode 100644 tests/images/trident-testimage/base/files/use-grpc-client-commit.conf delete mode 100644 tests/images/trident-testimage/base/scripts/duid-type-to-link-layer.sh delete mode 100644 tests/images/trident-testimage/base/scripts/post-install.sh delete mode 100644 tests/images/trident-testimage/base/scripts/prepare-update-config-verity.sh delete mode 100644 tests/images/trident-testimage/base/scripts/update-host-status.sh diff --git a/tests/images/trident-testimage/base/baseimg-selinux.yaml b/tests/images/trident-testimage/base/baseimg-selinux.yaml index 3b54ab257..83ffc6c6d 100644 --- a/tests/images/trident-testimage/base/baseimg-selinux.yaml +++ b/tests/images/trident-testimage/base/baseimg-selinux.yaml @@ -1,60 +1,39 @@ # SELinux validation base image. -# Based on baseimg-usr-verity.yaml but with SELinux ENFORCING and only the -# public trident-selinux policy (no trident-test-selinux). Validates that -# the production SELinux policy is sufficient for the systemd-activated -# update path. +# Based on test-images platform-integration-images/trident-verity-testimage/usr/host.yaml +# with SELinux ENFORCING and only the public trident-selinux policy +# (no trident-test-selinux). Validates that the production SELinux policy +# is sufficient for the systemd-activated update path. storage: - bootType: efi - disks: - partitionTableType: gpt + maxSize: 5G partitions: - id: esp type: esp + size: 500M label: esp - size: 512M - - - id: boot-a - size: 256M - - - id: boot-b - size: 256M - - id: root-a - size: 4G + - id: boot + size: 150M - - id: root-b - size: 4G + - id: root + size: 2G - - id: usr-a + - id: usr-data + label: usr size: 1G - - id: usr-b - size: 1G - - - id: usr-hash-a + - id: usr-hash + label: usr-hash size: 128M - - id: usr-hash-b - size: 128M - - - id: trident - label: trident - size: 512M - - - id: home - label: home - size: 1G - - - id: srv - label: srv - size: 128M + bootType: efi verity: - - id: usrverity + - id: usr name: usr - dataDeviceId: usr-a - hashDeviceId: usr-hash-a + dataDeviceId: usr-data + hashDeviceId: usr-hash dataDeviceMountIdType: uuid hashDeviceMountIdType: uuid @@ -62,45 +41,24 @@ storage: - deviceId: esp type: fat32 mountPoint: - idType: part-label path: /boot/efi options: umask=0077 - - deviceId: boot-a + - deviceId: boot type: ext4 mountPoint: - idType: uuid path: /boot - - deviceId: usrverity + - deviceId: root type: ext4 mountPoint: - path: /usr - options: defaults,ro - - - deviceId: root-a - type: ext4 - mountPoint: - idType: uuid path: / - - deviceId: trident - type: ext4 - mountPoint: - idType: part-label - path: /var/lib/trident - - - deviceId: home - type: ext4 - mountPoint: - idType: part-label - path: /home - - - deviceId: srv + - deviceId: usr type: ext4 mountPoint: - idType: part-label - path: /srv + path: /usr + options: defaults,ro os: bootloader: @@ -110,71 +68,69 @@ os: selinux: mode: enforcing - uki: - mode: create kernelCommandLine: extraCommandLine: - console=tty0 - - console=tty1 - console=ttyS0 - - rd.debug - - loglevel=6 + - rd.info - log_buf_len=1M - - systemd.journald.forward_to_console=1 - rd.hostonly=0 packages: + remove: + - grub2-efi-binary + install: + - binutils + - curl - device-mapper - - dnf - efibootmgr - iproute - iptables - - jq - - kexec-tools - lvm2 + - mdadm + - netplan - openssh-server - - selinux-policy - - systemd-boot - systemd-udev + - tpm2-tools - trident-service # NOTE: trident-test-selinux is intentionally NOT installed. # This image validates the production SELinux policy alone. + - trident-static-pcrlock-files - veritysetup - vim - - netplan - remove: - - grub2-efi-binary - - additionalFiles: - - source: files/99-dhcp-eth0.network - destination: /etc/systemd/network/99-dhcp-eth0.network - - source: files/sudoers-wheel - destination: /etc/sudoers.d/wheel - # Trident update service template — runs updates via systemd domain - # transition (init_t -> trident_t), exercising the production SELinux path. - - source: files/trident-update@.service - destination: /usr/lib/systemd/system/trident-update@.service + - systemd-ukify + - systemd-boot + - audit + - selinux-policy-devel services: enable: - - kdump - trident - tridentd.socket + uki: + mode: create - users: - - name: testuser - secondaryGroups: - - wheel + additionalFiles: + - source: files/sudoers-wheel + destination: /etc/sudoers.d/wheel + - source: files/dracut-nohostonly.conf + destination: /usr/lib/dracut/dracut.conf.d/nohostonly.conf + # For tests, override the public trident.service behavior and use + # grpc-client commit. + - source: files/use-grpc-client-commit.conf + destination: /etc/systemd/system/trident.service.d/override.conf + # Trident update service template — runs updates via systemd domain + # transition (init_t -> trident_t), exercising the production SELinux path. + - source: files/trident-update@.service + destination: /usr/lib/systemd/system/trident-update@.service -scripts: - postCustomization: - - path: scripts/post-install.sh - - path: scripts/update-host-status.sh - - path: scripts/prepare-update-config-verity.sh - arguments: - - uki - - path: scripts/duid-type-to-link-layer.sh +output: + artifacts: + items: + - ukis + path: ./output previewFeatures: - uki + - output-artifacts diff --git a/tests/images/trident-testimage/base/files/99-dhcp-eth0.network b/tests/images/trident-testimage/base/files/99-dhcp-eth0.network deleted file mode 100644 index 5cef9e24f..000000000 --- a/tests/images/trident-testimage/base/files/99-dhcp-eth0.network +++ /dev/null @@ -1,6 +0,0 @@ -[Match] -Name=eth0 - -[Network] -DHCP=yes -IPv6AcceptRA=no \ No newline at end of file diff --git a/tests/images/trident-testimage/base/files/dracut-nohostonly.conf b/tests/images/trident-testimage/base/files/dracut-nohostonly.conf new file mode 100644 index 000000000..18912360c --- /dev/null +++ b/tests/images/trident-testimage/base/files/dracut-nohostonly.conf @@ -0,0 +1 @@ +hostonly="no" diff --git a/tests/images/trident-testimage/base/files/use-grpc-client-commit.conf b/tests/images/trident-testimage/base/files/use-grpc-client-commit.conf new file mode 100644 index 000000000..958e0095c --- /dev/null +++ b/tests/images/trident-testimage/base/files/use-grpc-client-commit.conf @@ -0,0 +1,5 @@ +[Service] +ExecStart= +ExecStart=trident grpc-client commit +StandardOutput=journal+console +StandardError=journal+console diff --git a/tests/images/trident-testimage/base/scripts/duid-type-to-link-layer.sh b/tests/images/trident-testimage/base/scripts/duid-type-to-link-layer.sh deleted file mode 100644 index 5c35e32cf..000000000 --- a/tests/images/trident-testimage/base/scripts/duid-type-to-link-layer.sh +++ /dev/null @@ -1 +0,0 @@ -sed -i 's/#DUIDType=vendor/DUIDType=link-layer/' /etc/systemd/networkd.conf \ No newline at end of file diff --git a/tests/images/trident-testimage/base/scripts/post-install.sh b/tests/images/trident-testimage/base/scripts/post-install.sh deleted file mode 100644 index b960507cd..000000000 --- a/tests/images/trident-testimage/base/scripts/post-install.sh +++ /dev/null @@ -1,2 +0,0 @@ -# Add the necessary directories for the audit logs so that auditd can start -mkdir -p /var/log/audit \ No newline at end of file diff --git a/tests/images/trident-testimage/base/scripts/prepare-update-config-verity.sh b/tests/images/trident-testimage/base/scripts/prepare-update-config-verity.sh deleted file mode 100644 index 600151fdd..000000000 --- a/tests/images/trident-testimage/base/scripts/prepare-update-config-verity.sh +++ /dev/null @@ -1,36 +0,0 @@ -CONFIG_PATH=/var/lib/trident/update-config.yaml -DOWNLOAD_URL_PREFIX="http://192.168.122.1:8000" - -cat < $CONFIG_PATH -image: - url: $DOWNLOAD_URL_PREFIX/verity.cosi - sha384: ignored -EOF - -INTERFACE_MASK='enp*' -if [ "$1" == "eth0" ]; then - INTERFACE_MASK="$1" -fi - -if [ "$1" != "uki" ]; then - cat <> $CONFIG_PATH -scripts: - postConfigure: - - name: rw-overlay - runOn: [all] - content: | - mkdir -p /var/lib/trident-overlay/etc-rw/upper && mkdir -p /var/lib/trident-overlay/etc-rw/work -EOF -fi - -cat <> $CONFIG_PATH -internalParams: - allowUnusedFilesystems: true -EOF - -if [ "$1" == "uki" ]; then - cat <> $CONFIG_PATH - uki: true - disableGrubNoprefixCheck: true -EOF -fi diff --git a/tests/images/trident-testimage/base/scripts/update-host-status.sh b/tests/images/trident-testimage/base/scripts/update-host-status.sh deleted file mode 100644 index 4a69a0221..000000000 --- a/tests/images/trident-testimage/base/scripts/update-host-status.sh +++ /dev/null @@ -1 +0,0 @@ -trident offline-initialize From 8fa01b7b1ac9797c4e4415691c4c8a4f5172eac2 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 20:17:04 -0700 Subject: [PATCH 30/59] refactor: move SELinux test image to test-images repo The SELinux test image definition now lives in the test-images repo at platform-integration-images/trident-verity-testimage/usr/host-public-selinux.yaml. Removed trident-testimage/ directory and testimages.py entry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/images/testimages.py | 7 - .../base/baseimg-selinux.yaml | 136 ------------------ .../base/files/dracut-nohostonly.conf | 1 - .../base/files/sudoers-wheel | 1 - .../base/files/trident-update@.service | 12 -- .../base/files/use-grpc-client-commit.conf | 5 - 6 files changed, 162 deletions(-) delete mode 100644 tests/images/trident-testimage/base/baseimg-selinux.yaml delete mode 100644 tests/images/trident-testimage/base/files/dracut-nohostonly.conf delete mode 100644 tests/images/trident-testimage/base/files/sudoers-wheel delete mode 100644 tests/images/trident-testimage/base/files/trident-update@.service delete mode 100644 tests/images/trident-testimage/base/files/use-grpc-client-commit.conf diff --git a/tests/images/testimages.py b/tests/images/testimages.py index 3d4220849..09fefe00d 100755 --- a/tests/images/testimages.py +++ b/tests/images/testimages.py @@ -95,13 +95,6 @@ requires_ukify=True, ssh_key="files/id_rsa.pub", ), - ImageConfig( - "trident-selinux-testimage", - base_image=BaseImage.QEMU_GUEST, - config="trident-testimage", - config_file="base/baseimg-selinux.yaml", - requires_ukify=True, - ), ImageConfig( "trident-vm-grub-verity-azure-testimage", base_image=BaseImage.CORE_SELINUX, diff --git a/tests/images/trident-testimage/base/baseimg-selinux.yaml b/tests/images/trident-testimage/base/baseimg-selinux.yaml deleted file mode 100644 index 83ffc6c6d..000000000 --- a/tests/images/trident-testimage/base/baseimg-selinux.yaml +++ /dev/null @@ -1,136 +0,0 @@ -# SELinux validation base image. -# Based on test-images platform-integration-images/trident-verity-testimage/usr/host.yaml -# with SELinux ENFORCING and only the public trident-selinux policy -# (no trident-test-selinux). Validates that the production SELinux policy -# is sufficient for the systemd-activated update path. -storage: - disks: - - partitionTableType: gpt - maxSize: 5G - partitions: - - id: esp - type: esp - size: 500M - label: esp - - - id: boot - size: 150M - - - id: root - size: 2G - - - id: usr-data - label: usr - size: 1G - - - id: usr-hash - label: usr-hash - size: 128M - - bootType: efi - - verity: - - id: usr - name: usr - dataDeviceId: usr-data - hashDeviceId: usr-hash - dataDeviceMountIdType: uuid - hashDeviceMountIdType: uuid - - filesystems: - - deviceId: esp - type: fat32 - mountPoint: - path: /boot/efi - options: umask=0077 - - - deviceId: boot - type: ext4 - mountPoint: - path: /boot - - - deviceId: root - type: ext4 - mountPoint: - path: / - - - deviceId: usr - type: ext4 - mountPoint: - path: /usr - options: defaults,ro - -os: - bootloader: - resetType: hard-reset - hostname: trident-selinux-testimg - - selinux: - mode: enforcing - - kernelCommandLine: - extraCommandLine: - - console=tty0 - - console=ttyS0 - - rd.info - - log_buf_len=1M - - rd.hostonly=0 - - packages: - remove: - - grub2-efi-binary - - install: - - binutils - - curl - - device-mapper - - efibootmgr - - iproute - - iptables - - lvm2 - - mdadm - - netplan - - openssh-server - - systemd-udev - - tpm2-tools - - trident-service - # NOTE: trident-test-selinux is intentionally NOT installed. - # This image validates the production SELinux policy alone. - - trident-static-pcrlock-files - - veritysetup - - vim - - systemd-ukify - - systemd-boot - - audit - - selinux-policy-devel - - services: - enable: - - trident - - tridentd.socket - uki: - mode: create - - additionalFiles: - - source: files/sudoers-wheel - destination: /etc/sudoers.d/wheel - - source: files/dracut-nohostonly.conf - destination: /usr/lib/dracut/dracut.conf.d/nohostonly.conf - # For tests, override the public trident.service behavior and use - # grpc-client commit. - - source: files/use-grpc-client-commit.conf - destination: /etc/systemd/system/trident.service.d/override.conf - # Trident update service template — runs updates via systemd domain - # transition (init_t -> trident_t), exercising the production SELinux path. - - source: files/trident-update@.service - destination: /usr/lib/systemd/system/trident-update@.service - -output: - artifacts: - items: - - ukis - path: ./output - -previewFeatures: - - uki - - output-artifacts diff --git a/tests/images/trident-testimage/base/files/dracut-nohostonly.conf b/tests/images/trident-testimage/base/files/dracut-nohostonly.conf deleted file mode 100644 index 18912360c..000000000 --- a/tests/images/trident-testimage/base/files/dracut-nohostonly.conf +++ /dev/null @@ -1 +0,0 @@ -hostonly="no" diff --git a/tests/images/trident-testimage/base/files/sudoers-wheel b/tests/images/trident-testimage/base/files/sudoers-wheel deleted file mode 100644 index c8b362960..000000000 --- a/tests/images/trident-testimage/base/files/sudoers-wheel +++ /dev/null @@ -1 +0,0 @@ -%wheel ALL=(ALL:ALL) NOPASSWD: ALL \ No newline at end of file diff --git a/tests/images/trident-testimage/base/files/trident-update@.service b/tests/images/trident-testimage/base/files/trident-update@.service deleted file mode 100644 index b623f7f7a..000000000 --- a/tests/images/trident-testimage/base/files/trident-update@.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Trident Update (%i) -After=network.target network-online.target tridentd.socket - -[Service] -Type=oneshot -EnvironmentFile=/var/lib/trident/update-env -ExecStart=trident grpc-client update -v ${TRIDENT_VERBOSITY} ${UPDATE_CONFIG} --allowed-operations %i -TimeoutStartSec=600 - -[Install] -WantedBy=multi-user.target diff --git a/tests/images/trident-testimage/base/files/use-grpc-client-commit.conf b/tests/images/trident-testimage/base/files/use-grpc-client-commit.conf deleted file mode 100644 index 958e0095c..000000000 --- a/tests/images/trident-testimage/base/files/use-grpc-client-commit.conf +++ /dev/null @@ -1,5 +0,0 @@ -[Service] -ExecStart= -ExecStart=trident grpc-client commit -StandardOutput=journal+console -StandardError=journal+console From 8e859cb655ec3122953b4bad0dc8a0726111507c Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 20:19:43 -0700 Subject: [PATCH 31/59] refactor: use stages/build_image/build-image.yml for SELinux test images Use the standard build_image template which integrates with test-images repo via @test-images resource. Removes the custom BuildSELinuxTestImages stage in favor of the shared TridentTestImg_trident_selinux_testimage stage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 42dc466ab..5c695965a 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -13,10 +13,6 @@ # (init_t -> trident_t), which is the production SELinux path. parameters: - - name: dependsOnStages - type: object - default: [] - - name: micBuildType displayName: MIC Build Type type: string @@ -32,29 +28,17 @@ parameters: default: "*.*.*" stages: - - stage: BuildSELinuxTestImages - displayName: Build SELinux Test Images - dependsOn: - - PrepareSSHKeys - - GetTridentBinaries_rpms_amd64 - - ${{ each stage in parameters.dependsOnStages }}: - - ${{ stage }} - - jobs: - - template: ../trident_images/build-image.yml - parameters: - label: selinux-testimage - makeTarget: artifacts/trident-selinux-testimage.cosi - baseimgType: qemu_guest - micBuildType: ${{ parameters.micBuildType }} - micVersion: ${{ parameters.micVersion }} - useStagedSshKeys: true - numClones: "2" + - template: ../build_image/build-image.yml + parameters: + imageName: trident-selinux-testimage + micBuildType: ${{ parameters.micBuildType }} + micVersion: ${{ parameters.micVersion }} + clones: 2 - stage: SELinuxUpdateValidation displayName: SELinux Policy Update Validation dependsOn: - - BuildSELinuxTestImages + - TridentTestImg_trident_selinux_testimage - BuildingTools - TridentTestImg_trident_installer @@ -101,7 +85,7 @@ stages: displayName: "Download SELinux test images" inputs: buildType: current - artifactName: image-selinux-testimage + artifactName: trident-selinux-testimage targetPath: "$(TRIDENT_SOURCE_DIR)/artifacts/test-image" - bash: | From 5d63a67c933641becda388fee6a6f751ddfc76cf Mon Sep 17 00:00:00 2001 From: bfjelds Date: Mon, 11 May 2026 20:21:07 -0700 Subject: [PATCH 32/59] revert: remove numClones/NUM_CLONES from trident pipeline and Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No longer needed — the build_image/build-image.yml template in the trident repo delegates to test-images which handles clones via its own build-image.yml template with the clones parameter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/trident_images/build-image.yml | 6 ----- .../trident-testimg-template.yml | 22 ++----------------- Makefile | 3 +-- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/.pipelines/templates/stages/trident_images/build-image.yml b/.pipelines/templates/stages/trident_images/build-image.yml index 92db5713a..6f70dafdc 100644 --- a/.pipelines/templates/stages/trident_images/build-image.yml +++ b/.pipelines/templates/stages/trident_images/build-image.yml @@ -73,11 +73,6 @@ parameters: type: number default: 20 - - name: numClones - displayName: "Number of image clones to produce" - type: string - default: "" - jobs: - job: PrepareImage_${{ replace(parameters.label, '-', '_') }} displayName: Prepare Image ${{ parameters.label }} @@ -147,4 +142,3 @@ jobs: - ${{ parameters.baseimgType }} useStagedSshKeys: ${{ parameters.useStagedSshKeys }} downloadTrident: ${{ parameters.downloadTrident }} - numClones: ${{ parameters.numClones }} diff --git a/.pipelines/templates/stages/trident_images/trident-testimg-template.yml b/.pipelines/templates/stages/trident_images/trident-testimg-template.yml index 4a7899899..2660aba09 100644 --- a/.pipelines/templates/stages/trident_images/trident-testimg-template.yml +++ b/.pipelines/templates/stages/trident_images/trident-testimg-template.yml @@ -108,10 +108,6 @@ parameters: type: boolean default: false - - name: numClones - type: string - default: "" - steps: - template: ../common_tasks/avoid-pypi-usage.yml @@ -285,10 +281,6 @@ steps: export MIC_ARCHITECTURE="linux/${{ parameters.micArchitecture }}" fi - if [[ -n "${{ parameters.numClones }}" ]]; then - export NUM_CLONES="${{ parameters.numClones }}" - fi - # Compress the full image & delete the uncompressed image make ${{ parameters.target }} workingDirectory: ${{ parameters.tridentSourceDirectory }} @@ -302,18 +294,8 @@ steps: if [ -d "build/${{ parameters.target }}" ]; then sudo mv -v build/${{ parameters.target }}/* "${{ parameters.outputDirectory }}/" else - # When clones are produced, the target is e.g. artifacts/foo.cosi but - # the generated files are artifacts/foo_0.cosi, artifacts/foo_1.cosi, etc. - # Use a glob on the base name to capture all clones. - target="${{ parameters.target }}" - base="${target%.*}" - ext="${target##*.}" - clones=( ${base}_*.${ext} ) - if [ -e "${clones[0]}" ]; then - sudo mv -v "${base}"_*.${ext} "${{ parameters.outputDirectory }}/" - else - sudo mv -v "${{ parameters.target }}" "${{ parameters.outputDirectory }}/" - fi + # Everything else is a file + sudo mv -v "${{ parameters.target }}" "${{ parameters.outputDirectory }}/" fi workingDirectory: ${{ parameters.tridentSourceDirectory }} displayName: "Copy artifacts to output directory" diff --git a/Makefile b/Makefile index cf14fa478..a7d72c274 100644 --- a/Makefile +++ b/Makefile @@ -954,8 +954,7 @@ artifacts/%.cosi artifacts/%.iso artifacts/%.vhdx: $$(shell ./tests/images/testi $* \ --output-dir ./artifacts \ $(if $(strip $(MIC_CONTAINER_IMAGE)),--container $(MIC_CONTAINER_IMAGE)) \ - $(if $(strip $(MIC_ARCHITECTURE)),--image-architecture $(MIC_ARCHITECTURE)) \ - $(if $(strip $(NUM_CLONES)),--clones $(NUM_CLONES)) + $(if $(strip $(MIC_ARCHITECTURE)),--image-architecture $(MIC_ARCHITECTURE)) MIC_CONTAINER_IMAGE ?= $(shell ./tests/images/testimages.py show-artifact customizer-container-full) artifacts/trident-functest.qcow2: $$(shell ./tests/images/testimages.py dependencies $$(basename $$(notdir $$@))) From e4a756a91457e97b98af0f52fca54bd80b631343 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 08:54:21 -0700 Subject: [PATCH 33/59] fix: capture journal and AVC log even when update stage fails The systemctl start failure exits the step before journal capture. Restructure to capture the exit code, always dump the journal and audit log, then fail at the end. This ensures we can diagnose SELinux denials when the service fails. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../testing_selinux/selinux-update-testing.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 5c695965a..c82de32d0 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -185,12 +185,22 @@ stages: "printf 'UPDATE_CONFIG=/var/lib/trident/update-config.yaml\nTRIDENT_VERBOSITY=DEBUG\n' | sudo tee /var/lib/trident/update-env" echo "=== Start trident-update@stage.service ===" + STAGE_RESULT=0 ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ - 'sudo systemctl start trident-update@stage.service' + 'sudo systemctl start trident-update@stage.service' || STAGE_RESULT=$? - echo "=== Stage service completed successfully ===" + echo "=== Service journal output ===" ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ - 'sudo journalctl -u trident-update@stage.service --no-pager' + 'sudo journalctl -u trident-update@stage.service --no-pager' || true + + echo "=== SELinux audit log ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo ausearch -m avc --start recent 2>&1' || true + + if [ "$STAGE_RESULT" -ne 0 ]; then + echo "##[error]trident-update@stage.service failed with exit code $STAGE_RESULT" + exit 1 + fi workingDirectory: $(TRIDENT_SOURCE_DIR) displayName: "🔄 Run update stage via systemd" timeoutInMinutes: 10 From 36a29489ac39896a1dafebcf9be3efd485bc10ba Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 09:42:24 -0700 Subject: [PATCH 34/59] fix: write update config on VM before starting update service The SELinux test image doesn't have prepare-update-config-verity.sh in postCustomization (it's based on host.yaml which doesn't include it). Write the update config via SSH before starting the service, pointing at the COSI served by netlaunch on the gateway. Also add ConnectTimeout to ausearch SSH call to prevent hangs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index c82de32d0..7f66e6c0b 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -179,6 +179,21 @@ stages: set -eux HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + # The VM's gateway is the host running netlaunch on port 4000 + GATEWAY_IP=$(ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + "ip route | grep default | awk '{print \$3}'") + + echo "=== Write update config on VM ===" + ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + "sudo tee /var/lib/trident/update-config.yaml <&1' || true + ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo ausearch -m avc --start recent 2>&1 || echo "No AVC denials found"' || true if [ "$STAGE_RESULT" -ne 0 ]; then echo "##[error]trident-update@stage.service failed with exit code $STAGE_RESULT" From 4418f691a22ce64557a980d5f6b955c2648d2147 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 10:18:45 -0700 Subject: [PATCH 35/59] fix: start netlisten to serve COSI files for update The VM needs to download the update COSI via HTTP. Start netlisten in a separate step before the update steps, serving artifacts/test-image on port 4000. The background process persists across pipeline steps. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../testing_selinux/selinux-update-testing.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 7f66e6c0b..5f581fa3a 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -175,11 +175,24 @@ stages: workingDirectory: $(TRIDENT_SOURCE_DIR) displayName: "🔒 Verify SELinux state" + - bash: | + set -eux + echo "=== Start netlisten to serve COSI files ===" + ./bin/netlisten --force-color \ + -s artifacts/test-image \ + -p 4000 > ./netlisten.log 2>&1 & + echo "netlisten PID: $!" + sleep 2 + echo "=== Verifying netlisten is serving ===" + curl -s -o /dev/null -w "%{http_code}" http://localhost:4000/files/ || true + workingDirectory: $(TRIDENT_SOURCE_DIR) + displayName: "🌐 Start netlisten file server" + - bash: | set -eux HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" - # The VM's gateway is the host running netlaunch on port 4000 + # The VM's gateway is the host running netlisten on port 4000 GATEWAY_IP=$(ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ "ip route | grep default | awk '{print \$3}'") @@ -212,6 +225,9 @@ stages: ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 -i "$SSH_KEY" testing-user@$HOST_IP \ 'sudo ausearch -m avc --start recent 2>&1 || echo "No AVC denials found"' || true + echo "=== netlisten log ===" + cat $(TRIDENT_SOURCE_DIR)/netlisten.log || true + if [ "$STAGE_RESULT" -ne 0 ]; then echo "##[error]trident-update@stage.service failed with exit code $STAGE_RESULT" exit 1 From 94a866e8024309b73f85a791cbdf7887ebbb3d7b Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 11:28:52 -0700 Subject: [PATCH 36/59] fix: use python3 http.server instead of netlisten for COSI serving netlisten has phonehome/logstream overhead and may not start cleanly as a background process. Use python3 -m http.server which is simple, reliable, and already available on the pipeline agent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 5f581fa3a..1bcca1b7d 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -177,16 +177,17 @@ stages: - bash: | set -eux - echo "=== Start netlisten to serve COSI files ===" - ./bin/netlisten --force-color \ - -s artifacts/test-image \ - -p 4000 > ./netlisten.log 2>&1 & - echo "netlisten PID: $!" + echo "=== Start HTTP file server for COSI files ===" + cd artifacts/test-image + python3 -m http.server 4000 > /tmp/fileserver.log 2>&1 & + echo "File server PID: $!" sleep 2 - echo "=== Verifying netlisten is serving ===" - curl -s -o /dev/null -w "%{http_code}" http://localhost:4000/files/ || true + echo "=== Verifying file server is serving ===" + curl -sf http://localhost:4000/ | head -5 + echo "=== Files available ===" + ls -lh workingDirectory: $(TRIDENT_SOURCE_DIR) - displayName: "🌐 Start netlisten file server" + displayName: "🌐 Start HTTP file server" - bash: | set -eux @@ -200,7 +201,7 @@ stages: ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ "sudo tee /var/lib/trident/update-config.yaml <&1 || echo "No AVC denials found"' || true - echo "=== netlisten log ===" - cat $(TRIDENT_SOURCE_DIR)/netlisten.log || true - if [ "$STAGE_RESULT" -ne 0 ]; then echo "##[error]trident-update@stage.service failed with exit code $STAGE_RESULT" exit 1 From 9e067129fb5718d5032e0e269470a9a699ff0d17 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 11:31:17 -0700 Subject: [PATCH 37/59] fix: switch back to netlisten with retry loop for startup Use netlisten to align with other tests. Add a retry loop (10 attempts x 2s) to wait for netlisten to start listening before proceeding. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 1bcca1b7d..072de87a8 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -177,17 +177,27 @@ stages: - bash: | set -eux - echo "=== Start HTTP file server for COSI files ===" - cd artifacts/test-image - python3 -m http.server 4000 > /tmp/fileserver.log 2>&1 & - echo "File server PID: $!" - sleep 2 - echo "=== Verifying file server is serving ===" - curl -sf http://localhost:4000/ | head -5 - echo "=== Files available ===" - ls -lh + echo "=== Start netlisten to serve COSI files ===" + ./bin/netlisten --force-color \ + -s artifacts/test-image \ + -p 4000 \ + --full-logstream ./netlisten-logstream.log \ + -m ./netlisten-metrics.jsonl > ./netlisten.log 2>&1 & + NETLISTEN_PID=$! + echo "netlisten PID: $NETLISTEN_PID" + + # Wait for netlisten to start listening + for i in $(seq 1 10); do + if curl -sf http://localhost:4000/files/ > /dev/null 2>&1; then + echo "netlisten is serving on port 4000" + break + fi + echo "Waiting for netlisten to start (attempt $i)..." + sleep 2 + done + curl -sf http://localhost:4000/files/ | head -5 || echo "WARNING: netlisten may not be serving" workingDirectory: $(TRIDENT_SOURCE_DIR) - displayName: "🌐 Start HTTP file server" + displayName: "🌐 Start netlisten file server" - bash: | set -eux @@ -201,7 +211,7 @@ stages: ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ "sudo tee /var/lib/trident/update-config.yaml < Date: Tue, 12 May 2026 11:33:34 -0700 Subject: [PATCH 38/59] fix: merge netlisten into same step as update invocation Background processes from & may not survive between pipeline steps. Start netlisten in the same bash step as the update service invocation, matching the pattern used by e2e-test-run.yml. Also start netlisten in the finalize step for post-reboot commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 072de87a8..e09d3a84a 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -177,6 +177,11 @@ stages: - bash: | set -eux + HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) + SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + GATEWAY_IP=$(ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + "ip route | grep default | awk '{print \$3}'") + echo "=== Start netlisten to serve COSI files ===" ./bin/netlisten --force-color \ -s artifacts/test-image \ @@ -195,17 +200,6 @@ stages: echo "Waiting for netlisten to start (attempt $i)..." sleep 2 done - curl -sf http://localhost:4000/files/ | head -5 || echo "WARNING: netlisten may not be serving" - workingDirectory: $(TRIDENT_SOURCE_DIR) - displayName: "🌐 Start netlisten file server" - - - bash: | - set -eux - HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) - SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" - # The VM's gateway is the host running netlisten on port 4000 - GATEWAY_IP=$(ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ - "ip route | grep default | awk '{print \$3}'") echo "=== Write update config on VM ===" ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ @@ -249,9 +243,21 @@ stages: HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + echo "=== Start netlisten for finalize ===" + # Kill any leftover netlisten from previous step + if pgrep netlisten > /dev/null; then pkill netlisten; fi + ./bin/netlisten --force-color \ + -s artifacts/test-image \ + -p 4000 \ + --full-logstream ./netlisten-finalize-logstream.log \ + -m ./netlisten-finalize-metrics.jsonl > ./netlisten-finalize.log 2>&1 & + for i in $(seq 1 10); do + if curl -sf http://localhost:4000/files/ > /dev/null 2>&1; then break; fi + sleep 2 + done + echo "=== Start trident-update@finalize.service ===" # Finalize triggers a reboot, so the SSH connection will drop. - # Use a timeout and ignore the connection drop. ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=5 -o ServerAliveCountMax=1 \ -i "$SSH_KEY" testing-user@$HOST_IP \ 'sudo systemctl start trident-update@finalize.service' || true From 795322979f6902534ed7cab6283331cb46f20ab1 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 13:10:35 -0700 Subject: [PATCH 39/59] fix: remove stdout redirect from netlisten, add crash detection netlisten was failing silently because stdout/stderr were redirected to a file. Remove the redirect so output appears in the pipeline log. Add kill -0 check to detect if netlisten crashed on startup. List serve directory contents for debugging. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index e09d3a84a..2fafd0bbe 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -183,16 +183,22 @@ stages: "ip route | grep default | awk '{print \$3}'") echo "=== Start netlisten to serve COSI files ===" + ls -lh artifacts/test-image/ ./bin/netlisten --force-color \ -s artifacts/test-image \ -p 4000 \ --full-logstream ./netlisten-logstream.log \ - -m ./netlisten-metrics.jsonl > ./netlisten.log 2>&1 & + -m ./netlisten-metrics.jsonl & NETLISTEN_PID=$! echo "netlisten PID: $NETLISTEN_PID" # Wait for netlisten to start listening for i in $(seq 1 10); do + if ! kill -0 $NETLISTEN_PID 2>/dev/null; then + echo "##[error]netlisten (PID $NETLISTEN_PID) exited prematurely" + wait $NETLISTEN_PID || true + break + fi if curl -sf http://localhost:4000/files/ > /dev/null 2>&1; then echo "netlisten is serving on port 4000" break @@ -250,7 +256,7 @@ stages: -s artifacts/test-image \ -p 4000 \ --full-logstream ./netlisten-finalize-logstream.log \ - -m ./netlisten-finalize-metrics.jsonl > ./netlisten-finalize.log 2>&1 & + -m ./netlisten-finalize-metrics.jsonl & for i in $(seq 1 10); do if curl -sf http://localhost:4000/files/ > /dev/null 2>&1; then break; fi sleep 2 From 6d6d2894341251b6b9bfb90d7b55c2dc0b8874dc Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 13:13:38 -0700 Subject: [PATCH 40/59] fix: fail fast if netlisten doesn't start Add hard failure if netlisten never becomes ready after 20 seconds. Dump process list and socket status for debugging. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 2fafd0bbe..c607c2297 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -193,6 +193,7 @@ stages: echo "netlisten PID: $NETLISTEN_PID" # Wait for netlisten to start listening + NETLISTEN_READY=false for i in $(seq 1 10); do if ! kill -0 $NETLISTEN_PID 2>/dev/null; then echo "##[error]netlisten (PID $NETLISTEN_PID) exited prematurely" @@ -201,11 +202,19 @@ stages: fi if curl -sf http://localhost:4000/files/ > /dev/null 2>&1; then echo "netlisten is serving on port 4000" + NETLISTEN_READY=true break fi echo "Waiting for netlisten to start (attempt $i)..." sleep 2 done + if [ "$NETLISTEN_READY" != "true" ]; then + echo "##[error]netlisten failed to start after 20 seconds" + # Check if process is still alive + ps aux | grep netlisten || true + ss -tlnp | grep 4000 || true + exit 1 + fi echo "=== Write update config on VM ===" ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ From 795d4134e0f630902d6236301ebe4d2a666c4ca7 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 13:15:59 -0700 Subject: [PATCH 41/59] fix: restore netlisten log redirect, copy logs to artifacts Keep netlisten output in log files but copy them to the artifact output directory for post-run debugging. Also dump netlisten.log in the fail-fast block. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index c607c2297..5a595e4a1 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -188,7 +188,7 @@ stages: -s artifacts/test-image \ -p 4000 \ --full-logstream ./netlisten-logstream.log \ - -m ./netlisten-metrics.jsonl & + -m ./netlisten-metrics.jsonl > ./netlisten.log 2>&1 & NETLISTEN_PID=$! echo "netlisten PID: $NETLISTEN_PID" @@ -210,7 +210,7 @@ stages: done if [ "$NETLISTEN_READY" != "true" ]; then echo "##[error]netlisten failed to start after 20 seconds" - # Check if process is still alive + cat ./netlisten.log || true ps aux | grep netlisten || true ss -tlnp | grep 4000 || true exit 1 @@ -265,7 +265,7 @@ stages: -s artifacts/test-image \ -p 4000 \ --full-logstream ./netlisten-finalize-logstream.log \ - -m ./netlisten-finalize-metrics.jsonl & + -m ./netlisten-finalize-metrics.jsonl > ./netlisten-finalize.log 2>&1 & for i in $(seq 1 10); do if curl -sf http://localhost:4000/files/ > /dev/null 2>&1; then break; fi sleep 2 @@ -318,6 +318,8 @@ stages: SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" mkdir -p $(ob_outputDirectory) + cp ./netlisten.log $(ob_outputDirectory)/netlisten.log || true + cp ./netlisten-finalize.log $(ob_outputDirectory)/netlisten-finalize.log || true ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ 'sudo ausearch -m avc 2>&1' > $(ob_outputDirectory)/audit-avc.log || true ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ From d819e2d55b543b305957a8ac7285efd622fc7b5b Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 13:17:57 -0700 Subject: [PATCH 42/59] fix: add SSH and step timeouts to Collect logs Add ConnectTimeout=10, ServerAliveInterval=5/CountMax=3 to SSH calls, and timeoutInMinutes=3 on the step. Use set -x instead of set -eux so partial failures don't prevent other log collection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 5a595e4a1..7f42584fd 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -313,19 +313,21 @@ stages: displayName: "✅ Validate update succeeded" - bash: | - set -eux + set -x HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=5 -o ServerAliveCountMax=3" mkdir -p $(ob_outputDirectory) cp ./netlisten.log $(ob_outputDirectory)/netlisten.log || true cp ./netlisten-finalize.log $(ob_outputDirectory)/netlisten-finalize.log || true - ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + ssh $SSH_OPTS -i "$SSH_KEY" testing-user@$HOST_IP \ 'sudo ausearch -m avc 2>&1' > $(ob_outputDirectory)/audit-avc.log || true - ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ + ssh $SSH_OPTS -i "$SSH_KEY" testing-user@$HOST_IP \ 'sudo journalctl --no-pager 2>&1' > $(ob_outputDirectory)/journal.log || true workingDirectory: $(TRIDENT_SOURCE_DIR) condition: succeededOrFailed() + timeoutInMinutes: 3 displayName: "📄 Collect logs" - bash: | From 1641659f71fa73331502fb44ef2ce346d500cd37 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 13:42:44 -0700 Subject: [PATCH 43/59] fix: add netlisten to Go tools download patterns Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../templates/stages/testing_selinux/selinux-update-testing.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 7f42584fd..26ee6a409 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -68,6 +68,7 @@ stages: artifactName: go-tools patterns: | netlaunch + netlisten storm-trident virtdeploy targetPath: "$(TRIDENT_SOURCE_DIR)/bin" From 6133b3dcf5148ee6a1c0f94291736440293deb38 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 14:29:56 -0700 Subject: [PATCH 44/59] fix: add timeout to ausearch SSH call in update stage step The ausearch command hangs for 10 minutes causing the step to timeout, even though staging succeeded. Wrap with 'timeout 30' and add SSH keepalive options. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 26ee6a409..e26b962b7 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -243,8 +243,9 @@ stages: 'sudo journalctl -u trident-update@stage.service --no-pager' || true echo "=== SELinux audit log ===" - ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 -i "$SSH_KEY" testing-user@$HOST_IP \ - 'sudo ausearch -m avc --start recent 2>&1 || echo "No AVC denials found"' || true + timeout 30 ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=5 -o ServerAliveCountMax=3 \ + -i "$SSH_KEY" testing-user@$HOST_IP \ + 'sudo ausearch -m avc --start recent 2>&1 || echo "No AVC denials found"' || echo "ausearch timed out" if [ "$STAGE_RESULT" -ne 0 ]; then echo "##[error]trident-update@stage.service failed with exit code $STAGE_RESULT" From c7c611bb5b70730902a6e4e147c7f6150b813220 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 15:01:29 -0700 Subject: [PATCH 45/59] fix: add SSH retry loop in validation step After reboot, sshd needs time to start. Retry SSH connection up to 30 times (5s intervals, ~2.5 min max) before running validation checks. Also add ConnectTimeout and timeout on ausearch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index e26b962b7..ba8d88cef 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -293,26 +293,35 @@ stages: set -eux HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + SSH_CMD="ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 -i $SSH_KEY testing-user@$HOST_IP" + + echo "=== Wait for SSH to become available ===" + for i in $(seq 1 30); do + if $SSH_CMD 'echo ssh_ready' 2>/dev/null; then + echo "SSH available after $i attempts" + break + fi + echo "Waiting for SSH (attempt $i/30)..." + sleep 5 + done echo "=== Verify VM is up after update ===" - ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ - 'hostname && uptime' + $SSH_CMD 'hostname && uptime' echo "=== Check SELinux is still enforcing ===" - ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ - 'sudo getenforce' + $SSH_CMD 'sudo getenforce' echo "=== Check for SELinux denials ===" - ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ - 'sudo ausearch -m avc --start recent 2>&1 || echo "No recent AVC denials"' + timeout 30 $SSH_CMD \ + 'sudo ausearch -m avc --start recent 2>&1 || echo "No recent AVC denials"' || echo "ausearch timed out" echo "=== Check active volume ===" - ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ - 'sudo trident get 2>&1 || echo "trident get completed"' + $SSH_CMD 'sudo trident get 2>&1 || echo "trident get completed"' echo "=== SELinux update validation PASSED ===" workingDirectory: $(TRIDENT_SOURCE_DIR) displayName: "✅ Validate update succeeded" + timeoutInMinutes: 5 - bash: | set -x From 7c08ca7cde6826a861614d680ea11f9c75b7b2fd Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 15:47:51 -0700 Subject: [PATCH 46/59] fix: truncate serial log before finalize to avoid stale login detection wait-for-login was matching the install boot's login prompt still in the serial log, returning immediately before the VM actually rebooted. Truncate the serial log before starting finalize so wait-for-login only sees the post-reboot login prompt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../stages/testing_selinux/selinux-update-testing.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index ba8d88cef..16c6af7e9 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -258,8 +258,19 @@ stages: - bash: | set -eux HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) + VM_NAME=$(jq -r '.virtualmachines[0].name' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + echo "=== Truncate serial log before finalize reboot ===" + SERIAL_LOG=$(sudo virsh dumpxml $VM_NAME | grep -oP "(?<=/dev/null || true + fi + echo "=== Start netlisten for finalize ===" # Kill any leftover netlisten from previous step if pgrep netlisten > /dev/null; then pkill netlisten; fi From f3f4a715da4a43611e428bcb4a3f403ad5cba7a0 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 16:27:09 -0700 Subject: [PATCH 47/59] fix: take only first serial log path from virsh dumpxml Multiple elements in the domain XML caused SERIAL_LOG to be a multi-line string. Use head -1 to get only the first match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../templates/stages/testing_selinux/selinux-update-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 16c6af7e9..e06701c51 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -262,7 +262,7 @@ stages: SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" echo "=== Truncate serial log before finalize reboot ===" - SERIAL_LOG=$(sudo virsh dumpxml $VM_NAME | grep -oP "(?<= Date: Tue, 12 May 2026 17:01:34 -0700 Subject: [PATCH 48/59] fix: re-resolve VM IP after reboot using virsh domifaddr After reboot, the VM may get a new DHCP lease or the old IP may not be routable yet. Query libvirt for the current VM IP instead of using the stale IP from virt-deploy-metadata.json. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index e06701c51..a4d863fe9 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -302,8 +302,26 @@ stages: - bash: | set -eux - HOST_IP=$(jq -r '.virtualmachines[0].ip' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) + VM_NAME=$(jq -r '.virtualmachines[0].name' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + + echo "=== Resolve VM IP after reboot ===" + # The VM may get a new DHCP lease after reboot. Query libvirt for the current IP. + HOST_IP="" + for i in $(seq 1 30); do + HOST_IP=$(sudo virsh domifaddr $VM_NAME 2>/dev/null | grep -oP '\d+\.\d+\.\d+\.\d+' | head -1) + if [ -n "$HOST_IP" ]; then + echo "VM IP resolved: $HOST_IP (attempt $i)" + break + fi + echo "Waiting for VM IP (attempt $i/30)..." + sleep 5 + done + if [ -z "$HOST_IP" ]; then + echo "##[error]Could not resolve VM IP after reboot" + exit 1 + fi + SSH_CMD="ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 -i $SSH_KEY testing-user@$HOST_IP" echo "=== Wait for SSH to become available ===" From a90bcee45642cd6a4ad40078e7e3a9caee061bf1 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 17:03:28 -0700 Subject: [PATCH 49/59] feat: add comprehensive diagnostics to validation step Host-side: VM domain state, interfaces, bridge config, ARP table, DHCP leases, serial log tail on IP resolution failure. VM-side: network info, SELinux modules, service statuses, recent journal. Ping check before SSH to distinguish network vs SSH issues. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index a4d863fe9..4ff721485 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -305,8 +305,17 @@ stages: VM_NAME=$(jq -r '.virtualmachines[0].name' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json) SSH_KEY="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/helpers/key" + echo "=== Host-side diagnostics ===" + echo "--- VM domain state ---" + sudo virsh domstate $VM_NAME || true + echo "--- VM domain interfaces ---" + sudo virsh domifaddr $VM_NAME || true + echo "--- Host bridge/network ---" + ip addr show | grep -A2 'virbr\|192.168' || true + echo "--- Host ARP table ---" + arp -an 2>/dev/null || ip neigh show || true + echo "=== Resolve VM IP after reboot ===" - # The VM may get a new DHCP lease after reboot. Query libvirt for the current IP. HOST_IP="" for i in $(seq 1 30); do HOST_IP=$(sudo virsh domifaddr $VM_NAME 2>/dev/null | grep -oP '\d+\.\d+\.\d+\.\d+' | head -1) @@ -319,9 +328,19 @@ stages: done if [ -z "$HOST_IP" ]; then echo "##[error]Could not resolve VM IP after reboot" + echo "--- virsh domiflist ---" + sudo virsh domiflist $VM_NAME || true + echo "--- virsh net-dhcp-leases ---" + sudo virsh net-dhcp-leases default || true + echo "--- Last 50 lines of serial log ---" + SERIAL_LOG=$(sudo virsh dumpxml $VM_NAME | grep -oP "(?<=/dev/null || true exit 1 fi + echo "=== Verify connectivity ===" + ping -c 2 -W 3 $HOST_IP || echo "WARNING: ping failed" + SSH_CMD="ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 -i $SSH_KEY testing-user@$HOST_IP" echo "=== Wait for SSH to become available ===" @@ -337,9 +356,15 @@ stages: echo "=== Verify VM is up after update ===" $SSH_CMD 'hostname && uptime' + echo "=== VM network info ===" + $SSH_CMD 'ip addr show; ip route show' || true + echo "=== Check SELinux is still enforcing ===" $SSH_CMD 'sudo getenforce' + echo "=== SELinux loaded modules ===" + $SSH_CMD 'sudo semodule -l | grep trident' || true + echo "=== Check for SELinux denials ===" timeout 30 $SSH_CMD \ 'sudo ausearch -m avc --start recent 2>&1 || echo "No recent AVC denials"' || echo "ausearch timed out" @@ -347,6 +372,12 @@ stages: echo "=== Check active volume ===" $SSH_CMD 'sudo trident get 2>&1 || echo "trident get completed"' + echo "=== Trident service status ===" + $SSH_CMD 'sudo systemctl status trident.service tridentd.socket trident-update@stage.service trident-update@finalize.service 2>&1' || true + + echo "=== Recent journal (last 50 lines) ===" + $SSH_CMD 'sudo journalctl --no-pager -n 50' || true + echo "=== SELinux update validation PASSED ===" workingDirectory: $(TRIDENT_SOURCE_DIR) displayName: "✅ Validate update succeeded" From 69e4eaa5be3491c5c28a1e1890ea8f4f2a677227 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 17:35:19 -0700 Subject: [PATCH 50/59] fix: wait for VM network after wait-for-login in finalize step wait-for-login returns when the serial console shows the login prompt, but networking (systemd-networkd, DHCP) hasn't started yet. Poll with ping (30 x 3s) after wait-for-login to ensure the VM is network-ready before the validation step runs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../testing_selinux/selinux-update-testing.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index 4ff721485..fea3f3d72 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -296,6 +296,18 @@ stages: sudo ./bin/storm-trident helper wait-for-login -a \ --vm-name "$(jq -r '.virtualmachines[0].name' $(TRIDENT_SOURCE_DIR)/tools/virt-deploy-metadata.json)" \ --artifacts-folder "$(ob_outputDirectory)" + + echo "=== Wait for VM network to come up ===" + VM_IP=$(sudo virsh domifaddr $VM_NAME 2>/dev/null | grep -oP '\d+\.\d+\.\d+\.\d+' | head -1) + echo "VM IP: $VM_IP" + for i in $(seq 1 30); do + if ping -c 1 -W 2 $VM_IP > /dev/null 2>&1; then + echo "VM responding to ping (attempt $i)" + break + fi + echo "Waiting for VM network (attempt $i/30)..." + sleep 3 + done workingDirectory: $(TRIDENT_SOURCE_DIR) displayName: "🔄 Run update finalize via systemd" timeoutInMinutes: 10 From 9eea4a403d1bfe24833034a17570c35b1a373b94 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 17:40:39 -0700 Subject: [PATCH 51/59] refactor: use 'trident update -v trace' instead of grpc-client Simpler invocation, trace-level logging for maximum diagnostics. Removes TRIDENT_VERBOSITY env var since verbosity is now hardcoded. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../templates/stages/testing_selinux/selinux-update-testing.yml | 2 +- packaging/systemd/trident-update@.service | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index fea3f3d72..d3499c4b7 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -231,7 +231,7 @@ stages: echo "=== Write update environment file ===" ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ - "printf 'UPDATE_CONFIG=/var/lib/trident/update-config.yaml\nTRIDENT_VERBOSITY=DEBUG\n' | sudo tee /var/lib/trident/update-env" + "printf 'UPDATE_CONFIG=/var/lib/trident/update-config.yaml\n' | sudo tee /var/lib/trident/update-env" echo "=== Start trident-update@stage.service ===" STAGE_RESULT=0 diff --git a/packaging/systemd/trident-update@.service b/packaging/systemd/trident-update@.service index b623f7f7a..c895cbc12 100644 --- a/packaging/systemd/trident-update@.service +++ b/packaging/systemd/trident-update@.service @@ -5,7 +5,7 @@ After=network.target network-online.target tridentd.socket [Service] Type=oneshot EnvironmentFile=/var/lib/trident/update-env -ExecStart=trident grpc-client update -v ${TRIDENT_VERBOSITY} ${UPDATE_CONFIG} --allowed-operations %i +ExecStart=trident update -v trace ${UPDATE_CONFIG} --allowed-operations %i TimeoutStartSec=600 [Install] From 70683576376931693b66bc7189d630ea5347ea7f Mon Sep 17 00:00:00 2001 From: bfjelds Date: Tue, 12 May 2026 17:44:56 -0700 Subject: [PATCH 52/59] fix: derive update config from install config with full os section Instead of handwriting a minimal update config, copy the full install trident-config.yaml (which includes os, storage, etc.) and update just the image URL and internalParams. This ensures the update has all the sections trident expects. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../selinux-update-testing.yml | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml index d3499c4b7..982efd799 100644 --- a/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml +++ b/.pipelines/templates/stages/testing_selinux/selinux-update-testing.yml @@ -217,17 +217,23 @@ stages: exit 1 fi - echo "=== Write update config on VM ===" + echo "=== Create update config from install config ===" + TRIDENT_CONFIG="$(TRIDENT_SOURCE_DIR)/tests/e2e_tests/trident_configurations/usr-verity/trident-config.yaml" + + # Start with the install config, replace the image URL for the update COSI + cp "$TRIDENT_CONFIG" /tmp/update-config.yaml + sudo yq -i ".image.url = \"http://${GATEWAY_IP}:4000/files/usrverity_v2.cosi\"" /tmp/update-config.yaml + sudo yq -i '.internalParams.allowUnusedFilesystems = true' /tmp/update-config.yaml + sudo yq -i '.internalParams.uki = true' /tmp/update-config.yaml + sudo yq -i '.internalParams.disableGrubNoprefixCheck = true' /tmp/update-config.yaml + + echo "=== Update config ===" + cat /tmp/update-config.yaml + + echo "=== Copy update config to VM ===" + scp -o StrictHostKeyChecking=no -i "$SSH_KEY" /tmp/update-config.yaml testing-user@$HOST_IP:/tmp/update-config.yaml ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" testing-user@$HOST_IP \ - "sudo tee /var/lib/trident/update-config.yaml < Date: Wed, 13 May 2026 08:00:37 -0700 Subject: [PATCH 53/59] feat: split RAID SELinux policies into trident-selinux-raid package Move RAID-only policies to a separate additive module: - mdadm exec/unit/runtime permissions (optional_policy block) - bootloader_t tmpfs access for RAID New packaging/selinux-policy-trident-raid/ with .te/.fc/.if files. New trident-selinux-raid subpackage in trident.spec that Requires trident-selinux. Only install on systems using RAID storage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packaging/rpm/trident.spec | 50 ++++++++++++++++++- .../trident-raid.fc | 2 + .../trident-raid.if | 8 +++ .../trident-raid.te | 32 ++++++++++++ packaging/selinux-policy-trident/trident.te | 19 ++----- 5 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 packaging/selinux-policy-trident-raid/trident-raid.fc create mode 100644 packaging/selinux-policy-trident-raid/trident-raid.if create mode 100644 packaging/selinux-policy-trident-raid/trident-raid.te diff --git a/packaging/rpm/trident.spec b/packaging/rpm/trident.spec index 1f0ac1433..75514e473 100644 --- a/packaging/rpm/trident.spec +++ b/packaging/rpm/trident.spec @@ -200,6 +200,41 @@ fi # ------------------------------------------------------------------------------ +%package selinux-raid +Summary: Trident RAID SELinux policy +BuildArch: noarch +Requires: %{name}-selinux +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description selinux-raid +RAID SELinux policy module for Trident. Provides mdadm and bootloader +permissions needed for RAID storage configurations. Only install on +systems that use RAID. + +%files selinux-raid +%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-raid.pp.bz2 +%{_datadir}/selinux/devel/include/distributed/%{name}-raid.if +%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{name}-raid + +%pre selinux-raid +%selinux_relabel_pre -s %{selinuxtype} + +%post selinux-raid +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{name}-raid.pp.bz2 + +%postun selinux-raid +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} %{name}-raid +fi + +%posttrans selinux-raid +%selinux_relabel_post -s %{selinuxtype} + +# ------------------------------------------------------------------------------ + %package static-pcrlock-files Summary: Statically defined .pcrlock files Requires: %{name} @@ -252,6 +287,15 @@ cp -p packaging/selinux-policy-trident/trident.te selinux/ make -f %{_datadir}/selinux/devel/Makefile %{name}.pp bzip2 -9 %{name}.pp +# Build RAID SELinux policy module +rm -f selinux/* +cp -p packaging/selinux-policy-trident-raid/trident-raid.fc selinux/ +cp -p packaging/selinux-policy-trident-raid/trident-raid.if selinux/ +cp -p packaging/selinux-policy-trident-raid/trident-raid.te selinux/ + +make -f %{_datadir}/selinux/devel/Makefile %{name}-raid.pp +bzip2 -9 %{name}-raid.pp + %check # Test the trident variable for the appropriate version %if %{undefined rpm_ver} @@ -280,7 +324,11 @@ install -D -m 755 target/release/%{name} %{buildroot}/%{_bindir}/%{name} # Copy Trident SELinux policy module to /usr/share/selinux/packages install -D -m 0644 %{name}.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{name}.pp.bz2 -install -D -p -m 0644 selinux/%{name}.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}.if +install -D -p -m 0644 packaging/selinux-policy-trident/%{name}.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}.if + +# Copy Trident RAID SELinux policy module +install -D -m 0644 %{name}-raid.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-raid.pp.bz2 +install -D -p -m 0644 packaging/selinux-policy-trident-raid/%{name}-raid.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}-raid.if mkdir -p %{buildroot}%{_unitdir} install -D -m 644 packaging/systemd/%{name}.service %{buildroot}%{_unitdir}/%{name}.service diff --git a/packaging/selinux-policy-trident-raid/trident-raid.fc b/packaging/selinux-policy-trident-raid/trident-raid.fc new file mode 100644 index 000000000..1a8d6d49e --- /dev/null +++ b/packaging/selinux-policy-trident-raid/trident-raid.fc @@ -0,0 +1,2 @@ +# trident-raid SELinux file contexts +# No additional file contexts needed — the base trident module defines all file labels. diff --git a/packaging/selinux-policy-trident-raid/trident-raid.if b/packaging/selinux-policy-trident-raid/trident-raid.if new file mode 100644 index 000000000..d97bcdc1c --- /dev/null +++ b/packaging/selinux-policy-trident-raid/trident-raid.if @@ -0,0 +1,8 @@ +## RAID SELinux interfaces for Trident +## +##

+## This module provides no public interfaces. +## It exists only to satisfy the SELinux build toolchain requirement +## for a .if file alongside the .te and .fc files. +##

+##
diff --git a/packaging/selinux-policy-trident-raid/trident-raid.te b/packaging/selinux-policy-trident-raid/trident-raid.te new file mode 100644 index 000000000..546d4b5a1 --- /dev/null +++ b/packaging/selinux-policy-trident-raid/trident-raid.te @@ -0,0 +1,32 @@ +policy_module(trident-raid, 1.0.0) + +######################################## +# +# RAID SELinux policy for Trident +# +# This module provides additional permissions needed for RAID support. +# It layers on top of the base trident policy module (trident.pp) +# and should only be installed on systems that use RAID storage. +# + +require { + type trident_t; + type bootloader_t; +} + +# Allow trident to execute mdadm, manage its unit files, and write to +# its runtime directory. +optional_policy(` + require { + type mdadm_exec_t; + type mdadm_unit_t; + type mdadm_runtime_t; + } + allow trident_t mdadm_exec_t:file { open read getattr map relabelto setattr unlink write execute execute_no_trans }; + allow trident_t mdadm_unit_t:file { getattr open read relabelto setattr unlink }; + allow trident_t mdadm_runtime_t:dir { add_name remove_name search write }; + raid_manage_mdadm_runtime_files(trident_t) +') + +# List the contents of generic tmpfs directories; required for RAID +fs_list_tmpfs(bootloader_t) diff --git a/packaging/selinux-policy-trident/trident.te b/packaging/selinux-policy-trident/trident.te index 196e58b44..585980e96 100644 --- a/packaging/selinux-policy-trident/trident.te +++ b/packaging/selinux-policy-trident/trident.te @@ -594,18 +594,9 @@ optional_policy(` } allow trident_t loadkeys_exec_t:file { execute getattr map open read relabelto setattr unlink write }; ') -optional_policy(` - require { - type trident_t; - type mdadm_exec_t; - type mdadm_unit_t; - type mdadm_runtime_t; - } - allow trident_t mdadm_exec_t:file { open read getattr map relabelto setattr unlink write execute execute_no_trans }; - allow trident_t mdadm_unit_t:file { getattr open read relabelto setattr unlink }; - allow trident_t mdadm_runtime_t:dir { add_name remove_name search write }; - raid_manage_mdadm_runtime_files(trident_t) -') +# NOTE: RAID policies (mdadm) have been moved to the trident-raid SELinux +# module (packaging/selinux-policy-trident-raid/). Install the +# trident-selinux-raid package on systems that use RAID storage. #============= interfaces ============== ########################################### @@ -935,8 +926,8 @@ optional_policy(` # Additional permissions given to external domains # #============= bootloader_t ============== -# List the contents of generic tmpfs directories; required for RAID -fs_list_tmpfs(bootloader_t) +# NOTE: bootloader_t tmpfs access for RAID has been moved to the trident-raid +# SELinux module (packaging/selinux-policy-trident-raid/). #============= cloud_init_t ============== optional_policy(` From 1a6b79b05be3bf768e6d5589254560dd079b9d9c Mon Sep 17 00:00:00 2001 From: bfjelds Date: Wed, 13 May 2026 08:05:19 -0700 Subject: [PATCH 54/59] feat: split encryption & PCRlock SELinux policies into trident-selinux-encryption Move encryption/pcrlock-only policies to a separate additive module: - trident_t: systemd_pcrphase_exec_t execute, dev_rw_tpm - lvm_t: sem (encrypted volumes), key search (luksOpen), tpm write, tmp read - systemd_pcrphase_t: tmpfs access for PCR measurements New packaging/selinux-policy-trident-encryption/ with .te/.fc/.if files. New trident-selinux-encryption subpackage in trident.spec. Only install on systems using encryption or pcrlock features. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packaging/rpm/trident.spec | 48 +++++++++++++++++++ .../trident-encryption.fc | 2 + .../trident-encryption.if | 8 ++++ .../trident-encryption.te | 46 ++++++++++++++++++ packaging/selinux-policy-trident/trident.te | 24 ++++------ 5 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 packaging/selinux-policy-trident-encryption/trident-encryption.fc create mode 100644 packaging/selinux-policy-trident-encryption/trident-encryption.if create mode 100644 packaging/selinux-policy-trident-encryption/trident-encryption.te diff --git a/packaging/rpm/trident.spec b/packaging/rpm/trident.spec index 75514e473..e97da2079 100644 --- a/packaging/rpm/trident.spec +++ b/packaging/rpm/trident.spec @@ -235,6 +235,41 @@ fi # ------------------------------------------------------------------------------ +%package selinux-encryption +Summary: Trident encryption & PCRlock SELinux policy +BuildArch: noarch +Requires: %{name}-selinux +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description selinux-encryption +Encryption and PCRlock SELinux policy module for Trident. Provides TPM, +cryptsetup/LUKS, and systemd-pcrphase permissions. Only install on +systems that use encryption or pcrlock features. + +%files selinux-encryption +%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-encryption.pp.bz2 +%{_datadir}/selinux/devel/include/distributed/%{name}-encryption.if +%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{name}-encryption + +%pre selinux-encryption +%selinux_relabel_pre -s %{selinuxtype} + +%post selinux-encryption +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{name}-encryption.pp.bz2 + +%postun selinux-encryption +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} %{name}-encryption +fi + +%posttrans selinux-encryption +%selinux_relabel_post -s %{selinuxtype} + +# ------------------------------------------------------------------------------ + %package static-pcrlock-files Summary: Statically defined .pcrlock files Requires: %{name} @@ -296,6 +331,15 @@ cp -p packaging/selinux-policy-trident-raid/trident-raid.te selinux/ make -f %{_datadir}/selinux/devel/Makefile %{name}-raid.pp bzip2 -9 %{name}-raid.pp +# Build encryption SELinux policy module +rm -f selinux/* +cp -p packaging/selinux-policy-trident-encryption/trident-encryption.fc selinux/ +cp -p packaging/selinux-policy-trident-encryption/trident-encryption.if selinux/ +cp -p packaging/selinux-policy-trident-encryption/trident-encryption.te selinux/ + +make -f %{_datadir}/selinux/devel/Makefile %{name}-encryption.pp +bzip2 -9 %{name}-encryption.pp + %check # Test the trident variable for the appropriate version %if %{undefined rpm_ver} @@ -330,6 +374,10 @@ install -D -p -m 0644 packaging/selinux-policy-trident/%{name}.if %{buildroot}%{ install -D -m 0644 %{name}-raid.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-raid.pp.bz2 install -D -p -m 0644 packaging/selinux-policy-trident-raid/%{name}-raid.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}-raid.if +# Copy Trident encryption SELinux policy module +install -D -m 0644 %{name}-encryption.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-encryption.pp.bz2 +install -D -p -m 0644 packaging/selinux-policy-trident-encryption/%{name}-encryption.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}-encryption.if + mkdir -p %{buildroot}%{_unitdir} install -D -m 644 packaging/systemd/%{name}.service %{buildroot}%{_unitdir}/%{name}.service install -D -m 644 packaging/systemd/%{name}-install.service %{buildroot}%{_unitdir}/%{name}-install.service diff --git a/packaging/selinux-policy-trident-encryption/trident-encryption.fc b/packaging/selinux-policy-trident-encryption/trident-encryption.fc new file mode 100644 index 000000000..1541c9ccb --- /dev/null +++ b/packaging/selinux-policy-trident-encryption/trident-encryption.fc @@ -0,0 +1,2 @@ +# trident-encryption SELinux file contexts +# No additional file contexts needed — the base trident module defines all file labels. diff --git a/packaging/selinux-policy-trident-encryption/trident-encryption.if b/packaging/selinux-policy-trident-encryption/trident-encryption.if new file mode 100644 index 000000000..fa9702c8e --- /dev/null +++ b/packaging/selinux-policy-trident-encryption/trident-encryption.if @@ -0,0 +1,8 @@ +## Encryption & PCRlock SELinux interfaces for Trident +## +##

+## This module provides no public interfaces. +## It exists only to satisfy the SELinux build toolchain requirement +## for a .if file alongside the .te and .fc files. +##

+##
diff --git a/packaging/selinux-policy-trident-encryption/trident-encryption.te b/packaging/selinux-policy-trident-encryption/trident-encryption.te new file mode 100644 index 000000000..f02606aa9 --- /dev/null +++ b/packaging/selinux-policy-trident-encryption/trident-encryption.te @@ -0,0 +1,46 @@ +policy_module(trident-encryption, 1.0.0) + +######################################## +# +# Encryption & PCRlock SELinux policy for Trident +# +# This module provides additional permissions needed for encrypted volume +# support (cryptsetup/LUKS) and TPM-based PCR locking. It layers on top +# of the base trident policy module (trident.pp) and should only be +# installed on systems that use encryption or pcrlock features. +# + +require { + type trident_t; + type lvm_t; + type initrc_t; + type init_t; + type tpm_device_t; + type tmp_t; + type systemd_pcrphase_t; + type systemd_pcrphase_exec_t; + type tmpfs_t; +} + +#============= trident_t ============== +# Execute systemd-pcrphase for PCR lock measurements +allow trident_t systemd_pcrphase_exec_t:file { execute execute_no_trans getattr map open read }; + +# TPM device access for encryption key operations +dev_rw_tpm(trident_t) + +#============= lvm_t ============== +# Necessary for Trident to create encrypted volumes +allow lvm_t trident_t:sem { associate read unix_read unix_write write }; +allow lvm_t initrc_t:sem { associate read unix_read unix_write write }; + +# Necessary for cryptsetup luksOpen to succeed +allow lvm_t init_t:key search; +allow lvm_t tpm_device_t:chr_file write; + +# Necessary for veritysetup to be able to read a key file in /tmp +allow lvm_t tmp_t:file { getattr ioctl open read }; + +#============= systemd_pcrphase_t ============== +allow systemd_pcrphase_t tmpfs_t:dir { getattr open read search }; +allow systemd_pcrphase_t tmpfs_t:file { getattr lock open setattr write }; diff --git a/packaging/selinux-policy-trident/trident.te b/packaging/selinux-policy-trident/trident.te index 585980e96..df8d0bdc5 100644 --- a/packaging/selinux-policy-trident/trident.te +++ b/packaging/selinux-policy-trident/trident.te @@ -148,8 +148,6 @@ require { type systemd_networkd_runtime_t; type systemd_notify_exec_t; type systemd_passwd_agent_exec_t; - type systemd_pcrphase_t; - type systemd_pcrphase_exec_t; type systemd_pstore_exec_t; type systemd_resolved_exec_t; type systemd_rfkill_exec_t; @@ -489,7 +487,8 @@ allow trident_t systemd_networkd_runtime_t:dir { add_name getattr open read remo allow trident_t systemd_networkd_runtime_t:file { create getattr open read rename setattr unlink write }; allow trident_t systemd_notify_exec_t:file getattr; allow trident_t systemd_passwd_agent_exec_t:file { execute getattr map open read relabelto setattr unlink write }; -allow trident_t systemd_pcrphase_exec_t:file { execute execute_no_trans getattr map open read }; +# NOTE: systemd_pcrphase_exec_t permissions have been moved to the +# trident-encryption SELinux module (packaging/selinux-policy-trident-encryption/). allow trident_t pstore_t:dir search; allow trident_t systemd_pstore_exec_t:file { execute getattr }; allow trident_t systemd_resolved_exec_t:file { execute getattr }; @@ -835,7 +834,7 @@ dev_read_urand(trident_t) dev_relabelfrom_generic_chr_files(trident_t) dev_relabelfrom_vfio_dev(trident_t) dev_rw_nvram(trident_t) -dev_rw_tpm(trident_t) +# NOTE: dev_rw_tpm moved to trident-encryption SELinux module. dev_rw_vhost(trident_t) dev_search_sysfs(trident_t) dev_write_sysfs(trident_t) @@ -970,23 +969,16 @@ optional_policy(` ') #============= lvm_t ============== -# This is necessary for Trident to create encrypted volumes -allow lvm_t trident_t:sem { associate read unix_read unix_write write }; -allow lvm_t initrc_t:sem { associate read unix_read unix_write write }; - -# These permissions are necessary for cryptsetup luksOpen to succeed. -allow lvm_t init_t:key search; # Allows LVM to write to search the kernel keyring. -allow lvm_t tpm_device_t:chr_file write; # Allows LVM to write to the TPM device. - -# This is necessary for veritysetup to be able to read a key file in /tmp. -allow lvm_t tmp_t:file { getattr ioctl open read }; +# NOTE: Encryption-related lvm_t permissions (sem, key, tpm, tmp) have been +# moved to the trident-encryption SELinux module +# (packaging/selinux-policy-trident-encryption/). #============= mount_t ============= allow mount_t trident_var_lib_t:dir mounton; #============= systemd_pcrphase_t ============== -allow systemd_pcrphase_t tmpfs_t:dir { getattr open read search }; -allow systemd_pcrphase_t tmpfs_t:file { getattr lock open setattr write }; +# NOTE: systemd_pcrphase_t permissions have been moved to the +# trident-encryption SELinux module (packaging/selinux-policy-trident-encryption/). #============= rpm_t ============== optional_policy(` From 1d90de7e78dd47aadf5f87c2b3156891774c3eb6 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Wed, 13 May 2026 08:20:33 -0700 Subject: [PATCH 55/59] feat: split GRUB & dracut SELinux policies into trident-selinux-grub Move GRUB+dracut-only policies to a separate additive module: - bootloader_exec (GRUB tool execution) - boot_t dir/file management (/boot) - files_create_boot_dirs, files_manage_boot_files - loadkeys_exec_t and loadkeys_t optional blocks Not needed on UKI/systemd-boot systems where trident skips GRUB config, initrd regeneration, and /boot management entirely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packaging/rpm/trident.spec | 48 +++++++++++++++++++ .../trident-grub.fc | 2 + .../trident-grub.if | 8 ++++ .../trident-grub.te | 46 ++++++++++++++++++ packaging/selinux-policy-trident/trident.te | 32 ++++--------- 5 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 packaging/selinux-policy-trident-grub/trident-grub.fc create mode 100644 packaging/selinux-policy-trident-grub/trident-grub.if create mode 100644 packaging/selinux-policy-trident-grub/trident-grub.te diff --git a/packaging/rpm/trident.spec b/packaging/rpm/trident.spec index e97da2079..9d92a45b7 100644 --- a/packaging/rpm/trident.spec +++ b/packaging/rpm/trident.spec @@ -270,6 +270,41 @@ fi # ------------------------------------------------------------------------------ +%package selinux-grub +Summary: Trident GRUB & dracut SELinux policy +BuildArch: noarch +Requires: %{name}-selinux +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description selinux-grub +GRUB and dracut SELinux policy module for Trident. Provides bootloader +execution, /boot management, and loadkeys permissions needed for +GRUB-based boot. Not needed on UKI/systemd-boot systems. + +%files selinux-grub +%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-grub.pp.bz2 +%{_datadir}/selinux/devel/include/distributed/%{name}-grub.if +%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{name}-grub + +%pre selinux-grub +%selinux_relabel_pre -s %{selinuxtype} + +%post selinux-grub +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{name}-grub.pp.bz2 + +%postun selinux-grub +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} %{name}-grub +fi + +%posttrans selinux-grub +%selinux_relabel_post -s %{selinuxtype} + +# ------------------------------------------------------------------------------ + %package static-pcrlock-files Summary: Statically defined .pcrlock files Requires: %{name} @@ -340,6 +375,15 @@ cp -p packaging/selinux-policy-trident-encryption/trident-encryption.te selinux/ make -f %{_datadir}/selinux/devel/Makefile %{name}-encryption.pp bzip2 -9 %{name}-encryption.pp +# Build GRUB SELinux policy module +rm -f selinux/* +cp -p packaging/selinux-policy-trident-grub/trident-grub.fc selinux/ +cp -p packaging/selinux-policy-trident-grub/trident-grub.if selinux/ +cp -p packaging/selinux-policy-trident-grub/trident-grub.te selinux/ + +make -f %{_datadir}/selinux/devel/Makefile %{name}-grub.pp +bzip2 -9 %{name}-grub.pp + %check # Test the trident variable for the appropriate version %if %{undefined rpm_ver} @@ -378,6 +422,10 @@ install -D -p -m 0644 packaging/selinux-policy-trident-raid/%{name}-raid.if %{bu install -D -m 0644 %{name}-encryption.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-encryption.pp.bz2 install -D -p -m 0644 packaging/selinux-policy-trident-encryption/%{name}-encryption.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}-encryption.if +# Copy Trident GRUB SELinux policy module +install -D -m 0644 %{name}-grub.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-grub.pp.bz2 +install -D -p -m 0644 packaging/selinux-policy-trident-grub/%{name}-grub.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}-grub.if + mkdir -p %{buildroot}%{_unitdir} install -D -m 644 packaging/systemd/%{name}.service %{buildroot}%{_unitdir}/%{name}.service install -D -m 644 packaging/systemd/%{name}-install.service %{buildroot}%{_unitdir}/%{name}-install.service diff --git a/packaging/selinux-policy-trident-grub/trident-grub.fc b/packaging/selinux-policy-trident-grub/trident-grub.fc new file mode 100644 index 000000000..012a74899 --- /dev/null +++ b/packaging/selinux-policy-trident-grub/trident-grub.fc @@ -0,0 +1,2 @@ +# trident-grub SELinux file contexts +# No additional file contexts needed — the base trident module defines all file labels. diff --git a/packaging/selinux-policy-trident-grub/trident-grub.if b/packaging/selinux-policy-trident-grub/trident-grub.if new file mode 100644 index 000000000..192d14882 --- /dev/null +++ b/packaging/selinux-policy-trident-grub/trident-grub.if @@ -0,0 +1,8 @@ +## GRUB & dracut SELinux interfaces for Trident +## +##

+## This module provides no public interfaces. +## It exists only to satisfy the SELinux build toolchain requirement +## for a .if file alongside the .te and .fc files. +##

+##
diff --git a/packaging/selinux-policy-trident-grub/trident-grub.te b/packaging/selinux-policy-trident-grub/trident-grub.te new file mode 100644 index 000000000..75f3e7f6f --- /dev/null +++ b/packaging/selinux-policy-trident-grub/trident-grub.te @@ -0,0 +1,46 @@ +policy_module(trident-grub, 1.0.0) + +######################################## +# +# GRUB & dracut SELinux policy for Trident +# +# This module provides additional permissions needed for GRUB-based boot +# management and dracut initrd regeneration. It layers on top of the base +# trident policy module (trident.pp) and should only be installed on +# systems that use GRUB as their bootloader (not UKI/systemd-boot). +# + +require { + type trident_t; + type boot_t; +} + +#============= trident_t ============== +# Execute bootloader tools (grub-install, grub-mkconfig, etc.) +bootloader_exec(trident_t) + +# Manage /boot directory (kernel, initrd, grub configs) +allow trident_t boot_t:dir { mounton create relabelto }; +allow trident_t boot_t:file relabelto; + +# Create and manage boot directories and files +files_create_boot_dirs(trident_t) +files_manage_boot_files(trident_t) + +#============= loadkeys_t ============== +# loadkeys is used during dracut initrd generation for console keyboard config. +optional_policy(` + require { + type trident_t; + type loadkeys_exec_t; + } + allow trident_t loadkeys_exec_t:file { execute getattr map open read relabelto setattr unlink write }; +') +optional_policy(` + require { + type trident_t; + type loadkeys_t; + } + files_read_default_symlinks(loadkeys_t) + fs_search_tmpfs(loadkeys_t) +') diff --git a/packaging/selinux-policy-trident/trident.te b/packaging/selinux-policy-trident/trident.te index df8d0bdc5..b26c7941b 100644 --- a/packaging/selinux-policy-trident/trident.te +++ b/packaging/selinux-policy-trident/trident.te @@ -27,9 +27,7 @@ require { type auditctl_exec_t; type auditd_exec_t; type auditd_unit_t; - type boot_t; type bpf_t; - type bootloader_t; type chfn_exec_t; type chkpwd_exec_t; @@ -249,8 +247,8 @@ allow trident_t auditd_unit_t:file getattr; allow trident_t admin_passwd_exec_t:file getattr; allow trident_t anacron_exec_t:file getattr; allow trident_t audisp_remote_exec_t:file getattr; -allow trident_t boot_t:dir { mounton create relabelto }; -allow trident_t boot_t:file relabelto; +# NOTE: boot_t permissions have been moved to the trident-grub SELinux module +# (packaging/selinux-policy-trident-grub/). allow trident_t bpf_t:dir search; optional_policy(` require { @@ -586,13 +584,9 @@ optional_policy(` } allow trident_t dhcpd_unit_t:file getattr; ') -optional_policy(` - require { - type trident_t; - type loadkeys_exec_t; - } - allow trident_t loadkeys_exec_t:file { execute getattr map open read relabelto setattr unlink write }; -') +# NOTE: loadkeys_exec_t permissions have been moved to the trident-grub +# SELinux module (packaging/selinux-policy-trident-grub/). + # NOTE: RAID policies (mdadm) have been moved to the trident-raid SELinux # module (packaging/selinux-policy-trident-raid/). Install the # trident-selinux-raid package on systems that use RAID storage. @@ -627,7 +621,7 @@ userdom_relabelto_user_home_dirs(trident_t) ########################################### # System Services and Daemons ########################################### -bootloader_exec(trident_t) +# NOTE: bootloader_exec moved to trident-grub SELinux module. optional_policy(` require { type chronyd_exec_t; @@ -685,11 +679,11 @@ optional_policy(` ########################################### # File System Operations ########################################### -files_create_boot_dirs(trident_t) +# NOTE: files_create_boot_dirs and files_manage_boot_files moved to trident-grub SELinux module. files_list_kernel_modules(trident_t) files_list_spool(trident_t) files_list_var(trident_t) -files_manage_boot_files(trident_t) +# NOTE: files_manage_boot_files moved to trident-grub SELinux module. files_manage_etc_dirs(trident_t) files_manage_etc_symlinks(trident_t) files_mounton_runtime_dirs(trident_t) @@ -959,14 +953,8 @@ fs_manage_tmpfs_dirs(fsadm_t) fs_manage_tmpfs_files(fsadm_t) #============= loadkeys_t ============== -optional_policy(` - require { - type trident_t; - type loadkeys_t; - } - files_read_default_symlinks(loadkeys_t) - fs_search_tmpfs(loadkeys_t) -') +# NOTE: loadkeys_t permissions have been moved to the trident-grub +# SELinux module (packaging/selinux-policy-trident-grub/). #============= lvm_t ============== # NOTE: Encryption-related lvm_t permissions (sem, key, tpm, tmp) have been From f6da56f769ae205181d3a6e9a07bdea996e595cd Mon Sep 17 00:00:00 2001 From: bfjelds Date: Wed, 13 May 2026 09:12:44 -0700 Subject: [PATCH 56/59] docs: improve comments for optional relabeling policies Replace vague 'Policies below must be optional for Steamboat' with a clear explanation that these policies exist because trident encounters files/dirs owned by optional package types during OS provisioning and relabeling (bluetooth, colord, dhcpd, etc.). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packaging/selinux-policy-trident/trident.te | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packaging/selinux-policy-trident/trident.te b/packaging/selinux-policy-trident/trident.te index b26c7941b..1a7e58c3c 100644 --- a/packaging/selinux-policy-trident/trident.te +++ b/packaging/selinux-policy-trident/trident.te @@ -562,7 +562,11 @@ optional_policy(` allow trident_t cloud_init_state_t:file getattr; ') -# Policies below must be optional for Steamboat +# Optional policies for types that may not exist on all images. +# Trident encounters these files/dirs during OS provisioning and relabeling. +# These types are defined by packages that may or may not be installed +# (e.g., bluetooth, colord, dhcpd). The policies are optional so SELinux +# ignores them when the referenced types don't exist on the target system. optional_policy(` require { type trident_t; From cc234e9f43f449153f5157e91e19ecbbc612f273 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Wed, 13 May 2026 09:17:28 -0700 Subject: [PATCH 57/59] docs: add explanatory comments to all SELinux policy rules Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../trident-encryption.te | 1 + packaging/selinux-policy-trident/trident.te | 29 +++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/packaging/selinux-policy-trident-encryption/trident-encryption.te b/packaging/selinux-policy-trident-encryption/trident-encryption.te index f02606aa9..665a6d6e5 100644 --- a/packaging/selinux-policy-trident-encryption/trident-encryption.te +++ b/packaging/selinux-policy-trident-encryption/trident-encryption.te @@ -42,5 +42,6 @@ allow lvm_t tpm_device_t:chr_file write; allow lvm_t tmp_t:file { getattr ioctl open read }; #============= systemd_pcrphase_t ============== +# Record PCR phase state in tmpfs while measuring encrypted boot progress. allow systemd_pcrphase_t tmpfs_t:dir { getattr open read search }; allow systemd_pcrphase_t tmpfs_t:file { getattr lock open setattr write }; diff --git a/packaging/selinux-policy-trident/trident.te b/packaging/selinux-policy-trident/trident.te index 1a7e58c3c..31996eda6 100644 --- a/packaging/selinux-policy-trident/trident.te +++ b/packaging/selinux-policy-trident/trident.te @@ -213,8 +213,8 @@ type_transition trident_t fsadm_exec_t:process fsadm_t; # dac_override and dac_read_search - allow access files and directories without necessary DAC permissions # sys_ptrace - allow trident_t to trace or debug other processes # sys_rawio - allow trident_t to perform I/O operations directly on hardware devices +# Core runtime permissions for provisioning, storage orchestration, network reconfiguration, and host updates. allow trident_t self:capability { dac_override dac_read_search sys_ptrace sys_rawio }; - allow trident_t self:alg_socket { accept bind create read write }; allow trident_t self:capability { audit_write chown mknod net_admin sys_chroot sys_resource sys_admin fowner fsetid sys_boot ipc_lock sys_nice linux_immutable sys_module setgid setuid }; allow trident_t self:fifo_file manage_fifo_file_perms; @@ -239,6 +239,7 @@ allow trident_t trident_var_lib_t:file { getattr setattr create open read write # Allow Trident to relabel its executable allow trident_t trident_exec_t:file relabelto; +# Inspect service metadata and package state Trident encounters while reconciling a host image. allow trident_t audit_spool_t:dir { getattr open read relabelto }; allow trident_t auditctl_exec_t:file getattr; allow trident_t auditd_exec_t:file getattr; @@ -278,6 +279,7 @@ allow trident_t crack_db_t:dir { getattr open search read }; allow trident_t crack_db_t:file getattr; allow trident_t crack_db_t:lnk_file getattr; allow trident_t crack_exec_t:file getattr; +# Traverse mixed filesystem labels and home roots while relabeling provisioned files. allow trident_t cron_spool_t:dir { read relabelto }; allow trident_t crond_unit_t:file { getattr read open ioctl }; allow trident_t dbusd_unit_t:file getattr; @@ -318,6 +320,7 @@ optional_policy(` allow trident_t groupadd_exec_t:file getattr; allow trident_t home_root_t:dir { mounton read relabelto add_name create relabelfrom setattr write }; allow trident_t home_root_t:file { create getattr ioctl open relabelfrom setattr read write }; +# Reach init, kernel, storage, and proxy helpers while applying OS updates and customizations. allow trident_t http_cache_port_t:tcp_socket name_connect; # Allow Trident to initiate connection to HTTP proxy port allow trident_t http_port_t:tcp_socket name_connect; allow trident_t init_exec_t:file { execute getattr map open read relabelto setattr unlink write }; @@ -394,6 +397,7 @@ optional_policy(` } allow trident_t oddjob_mkhomedir_exec_t:file getattr; ') +# Update procfs state, accounts, and SSH assets during provisioning and repair flows. allow trident_t power_unit_t:file { getattr open read relabelto setattr unlink }; allow trident_t proc_t:dir read; allow trident_t proc_t:file { getattr open read ioctl }; @@ -440,6 +444,7 @@ allow trident_t sshd_key_t:file { getattr manage_file_perms }; # Allow Trident t allow trident_t sshd_keygen_unit_t:file getattr; allow trident_t sshd_unit_t:file getattr; allow trident_t sulogin_exec_t:file { execute getattr map open read relabelto setattr unlink write }; +# Run sysctl and systemd helpers while regenerating host configuration after an update. allow trident_t sysctl_fs_t:dir search; allow trident_t sysctl_fs_t:file { getattr ioctl open read }; allow trident_t sysctl_kernel_t:dir search; @@ -498,6 +503,7 @@ allow trident_t systemd_stdio_bridge_exec_t:file getattr; allow trident_t systemd_sysctl_exec_t:file { execute getattr map open read relabelto setattr unlink write }; allow trident_t systemd_sysusers_exec_t:file { execute getattr map open read relabelto setattr unlink write }; allow trident_t systemd_tmpfiles_exec_t:file { execute getattr map open read relabelto setattr unlink write }; +# Manage transient, unlabeled, and /usr-/var-backed content Trident creates during upgrades. allow trident_t systemd_unit_t:dir { read add_name create write reparent rename setattr relabelfrom }; allow trident_t systemd_unit_t:file { getattr ioctl link open read relabelto relabelfrom rename setattr unlink write create }; allow trident_t systemd_unit_t:lnk_file { getattr read create relabelfrom }; @@ -550,7 +556,7 @@ allow trident_t var_run_t:sock_file write; allow trident_t var_spool_t:dir relabelto; allow trident_t wtmp_t:file relabelto; -# Optional policies for modifying cloud-init settings +# Inspect and update cloud-init state during first-boot provisioning. optional_policy(` require { type cloud_init_exec_t; @@ -599,6 +605,7 @@ optional_policy(` ########################################### # Authentication and User Management ########################################### +# Manage users, passwords, and home directories during OS provisioning. auth_create_faillog_files(trident_t) auth_exec_pam(trident_t) auth_login_entry_type(trident_t) @@ -625,6 +632,7 @@ userdom_relabelto_user_home_dirs(trident_t) ########################################### # System Services and Daemons ########################################### +# Start helpers and inspect daemon state while Trident configures host services. # NOTE: bootloader_exec moved to trident-grub SELinux module. optional_policy(` require { @@ -683,6 +691,7 @@ optional_policy(` ########################################### # File System Operations ########################################### +# Read, mount, and relabel filesystems while staging A/B updates and extensions. # NOTE: files_create_boot_dirs and files_manage_boot_files moved to trident-grub SELinux module. files_list_kernel_modules(trident_t) files_list_spool(trident_t) @@ -731,6 +740,7 @@ mount_list_runtime(trident_t) ########################################### # Network Management ########################################### +# Reconfigure host networking, DHCP data, and firewall rules during provisioning. iptables_exec(trident_t) iptables_read_config(trident_t) iptables_status(trident_t) @@ -743,6 +753,7 @@ sysnet_write_config(trident_t) ########################################### # Storage Management ########################################### +# Manage loop, LVM, and filesystem helpers while laying down root and extension volumes. dev_rw_loop_control(trident_t) dev_rw_lvm_control(trident_t) lvm_exec(trident_t) @@ -759,6 +770,7 @@ storage_raw_write_fixed_disk(trident_t) ########################################### # SELinux Management ########################################### +# Relabel updated filesystem content and reload policy after provisioning or upgrade steps. corecmd_relabel_bin_files(trident_t) files_relabel_etc_files(trident_t) files_relabel_kernel_modules(trident_t) @@ -788,6 +800,7 @@ udev_relabel_rules_files(trident_t) ########################################### # Package Management ########################################### +# Read and update RPM metadata while installing or validating host packages. optional_policy(` require { type rpm_exec_t; @@ -806,6 +819,7 @@ optional_policy(` ########################################### # Device Management ########################################### +# Discover hardware and adjust device state as Trident prepares storage and boot media. corenet_getattr_ppp_dev(trident_t) corenet_read_tun_tap_dev(trident_t) dev_getattr_acpi_bios_dev(trident_t) @@ -847,6 +861,7 @@ udev_read_state(trident_t) ########################################### # System Command Execution ########################################### +# Execute core host utilities in place during provisioning and customization workflows. optional_policy(` require { type sudo_exec_t; @@ -886,6 +901,7 @@ optional_policy(` ########################################### # Logging and Monitoring ########################################### +# Read existing logs and emit diagnostics for servicing operations. logging_read_audit_config(trident_t) logging_read_audit_log(trident_t) logging_relabelto_devlog_sock_files(trident_t) @@ -897,6 +913,7 @@ logging_manage_generic_logs(trident_t) ########################################### # Miscellaneous ########################################### +# Read optional platform assets that may appear on different image variants. optional_policy(` miscfiles_read_generic_tls_privkey(trident_t) ') @@ -927,6 +944,7 @@ optional_policy(` # SELinux module (packaging/selinux-policy-trident-raid/). #============= cloud_init_t ============== +# Let cloud-init finish first-boot setup on files Trident creates under /usr and unlabeled paths. optional_policy(` require { type cloud_init_t; @@ -940,6 +958,7 @@ optional_policy(` ') #============= fsadm_t ============== +# Allow mkfs/fsadm helpers spawned by Trident to manage EFI variables and loop-backed extension images. role unconfined_r types fsadm_t; # Get the attributes of efivarfs filesystems @@ -966,6 +985,7 @@ fs_manage_tmpfs_files(fsadm_t) # (packaging/selinux-policy-trident-encryption/). #============= mount_t ============= +# Let the mount helper mount Trident-managed images and volumes. allow mount_t trident_var_lib_t:dir mounton; #============= systemd_pcrphase_t ============== @@ -1000,14 +1020,17 @@ libs_manage_lib_dirs(semanage_t) libs_manage_lib_files(semanage_t) #============= setfiles_t ============== +# Let setfiles relabel special files Trident lays down during updates. allow setfiles_t proc_t:filesystem getattr; allow setfiles_t unlabeled_t:file { map open read }; allow setfiles_t container_var_lib_t:blk_file relabelto; #============= systemd_generator_t ============== +# Let systemd generators read home-root state after Trident provisions users and units. allow systemd_generator_t home_root_t:dir read; #============= udev_t ============== +# Allow udev helpers triggered by Trident storage changes to inspect provisioning state and extension images. optional_policy(` require { type cloud_init_t; @@ -1024,6 +1047,7 @@ allow udev_t trident_var_lib_t:file getattr; files_read_generic_tmp_files(udev_t) #============= udevadm_t ============== +# Allow udevadm runs initiated by Trident to rescan devices and rebuild runtime metadata. optional_policy(` require { type cgroup_t; @@ -1062,4 +1086,5 @@ optional_policy(` dev_search_sysfs(udevadm_t) #============= unlabeled_t ============== +# Associate tmpfs-backed content with unlabeled_t while Trident is relabeling fresh filesystems. fs_associate_tmpfs(unlabeled_t) \ No newline at end of file From f6f67902f3280ab1c8416582b8a5d4e14d2716ab Mon Sep 17 00:00:00 2001 From: bfjelds Date: Wed, 13 May 2026 09:27:56 -0700 Subject: [PATCH 58/59] feat: split cloud-init SELinux policies into trident-selinux-cloud-init Move all cloud-init interaction policies to a separate additive module: - trident_t: getattr on cloud_init_exec_t/cloud_init_state_t, ps_process_pattern - cloud_init_t: manage unlabeled/usr files trident creates - udev_t: use cloud_init_t fd/fifo during device events Install on any system using cloud-init (standard for Azure Linux). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packaging/rpm/trident.spec | 49 +++++++++++++++++++ .../trident-cloud-init.fc | 2 + .../trident-cloud-init.if | 8 +++ .../trident-cloud-init.te | 46 +++++++++++++++++ packaging/selinux-policy-trident/trident.te | 42 ++-------------- 5 files changed, 110 insertions(+), 37 deletions(-) create mode 100644 packaging/selinux-policy-trident-cloud-init/trident-cloud-init.fc create mode 100644 packaging/selinux-policy-trident-cloud-init/trident-cloud-init.if create mode 100644 packaging/selinux-policy-trident-cloud-init/trident-cloud-init.te diff --git a/packaging/rpm/trident.spec b/packaging/rpm/trident.spec index 9d92a45b7..60542ee82 100644 --- a/packaging/rpm/trident.spec +++ b/packaging/rpm/trident.spec @@ -305,6 +305,42 @@ fi # ------------------------------------------------------------------------------ +%package selinux-cloud-init +Summary: Trident cloud-init SELinux policy +BuildArch: noarch +Requires: %{name}-selinux +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description selinux-cloud-init +Cloud-init SELinux policy module for Trident. Provides permissions for +trident to interact with cloud-init during provisioning, and for +cloud-init to manage files trident creates. Install on any system +that uses cloud-init. + +%files selinux-cloud-init +%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-cloud-init.pp.bz2 +%{_datadir}/selinux/devel/include/distributed/%{name}-cloud-init.if +%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{name}-cloud-init + +%pre selinux-cloud-init +%selinux_relabel_pre -s %{selinuxtype} + +%post selinux-cloud-init +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{name}-cloud-init.pp.bz2 + +%postun selinux-cloud-init +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} %{name}-cloud-init +fi + +%posttrans selinux-cloud-init +%selinux_relabel_post -s %{selinuxtype} + +# ------------------------------------------------------------------------------ + %package static-pcrlock-files Summary: Statically defined .pcrlock files Requires: %{name} @@ -384,6 +420,15 @@ cp -p packaging/selinux-policy-trident-grub/trident-grub.te selinux/ make -f %{_datadir}/selinux/devel/Makefile %{name}-grub.pp bzip2 -9 %{name}-grub.pp +# Build cloud-init SELinux policy module +rm -f selinux/* +cp -p packaging/selinux-policy-trident-cloud-init/trident-cloud-init.fc selinux/ +cp -p packaging/selinux-policy-trident-cloud-init/trident-cloud-init.if selinux/ +cp -p packaging/selinux-policy-trident-cloud-init/trident-cloud-init.te selinux/ + +make -f %{_datadir}/selinux/devel/Makefile %{name}-cloud-init.pp +bzip2 -9 %{name}-cloud-init.pp + %check # Test the trident variable for the appropriate version %if %{undefined rpm_ver} @@ -426,6 +471,10 @@ install -D -p -m 0644 packaging/selinux-policy-trident-encryption/%{name}-encryp install -D -m 0644 %{name}-grub.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-grub.pp.bz2 install -D -p -m 0644 packaging/selinux-policy-trident-grub/%{name}-grub.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}-grub.if +# Copy Trident cloud-init SELinux policy module +install -D -m 0644 %{name}-cloud-init.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{name}-cloud-init.pp.bz2 +install -D -p -m 0644 packaging/selinux-policy-trident-cloud-init/%{name}-cloud-init.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}-cloud-init.if + mkdir -p %{buildroot}%{_unitdir} install -D -m 644 packaging/systemd/%{name}.service %{buildroot}%{_unitdir}/%{name}.service install -D -m 644 packaging/systemd/%{name}-install.service %{buildroot}%{_unitdir}/%{name}-install.service diff --git a/packaging/selinux-policy-trident-cloud-init/trident-cloud-init.fc b/packaging/selinux-policy-trident-cloud-init/trident-cloud-init.fc new file mode 100644 index 000000000..24e2e33b8 --- /dev/null +++ b/packaging/selinux-policy-trident-cloud-init/trident-cloud-init.fc @@ -0,0 +1,2 @@ +# trident-cloud-init SELinux file contexts +# No additional file contexts needed. diff --git a/packaging/selinux-policy-trident-cloud-init/trident-cloud-init.if b/packaging/selinux-policy-trident-cloud-init/trident-cloud-init.if new file mode 100644 index 000000000..4ea106f78 --- /dev/null +++ b/packaging/selinux-policy-trident-cloud-init/trident-cloud-init.if @@ -0,0 +1,8 @@ +## Cloud-init SELinux interfaces for Trident +## +##

+## This module provides no public interfaces. +## It exists only to satisfy the SELinux build toolchain requirement +## for a .if file alongside the .te and .fc files. +##

+##
diff --git a/packaging/selinux-policy-trident-cloud-init/trident-cloud-init.te b/packaging/selinux-policy-trident-cloud-init/trident-cloud-init.te new file mode 100644 index 000000000..c42772289 --- /dev/null +++ b/packaging/selinux-policy-trident-cloud-init/trident-cloud-init.te @@ -0,0 +1,46 @@ +policy_module(trident-cloud-init, 1.0.0) + +######################################## +# +# Cloud-init SELinux policy for Trident +# +# This module provides permissions for trident to interact with cloud-init +# during first-boot provisioning, and for cloud-init to manage files that +# trident creates. Install on any Azure Linux system that uses cloud-init. +# + +require { + type trident_t; + type cloud_init_t; + type cloud_init_exec_t; + type cloud_init_state_t; + type unlabeled_t; + type usr_t; + type udev_t; +} + +#============= trident_t ============== +# Inspect cloud-init binary and state during provisioning and relabeling. +allow trident_t cloud_init_exec_t:file getattr; +allow trident_t cloud_init_state_t:dir { list_dir_perms relabelto }; +allow trident_t cloud_init_state_t:lnk_file read_lnk_file_perms; +allow trident_t cloud_init_state_t:file getattr; + +# Read cloud-init process state to coordinate provisioning sequence. +ps_process_pattern(trident_t, cloud_init_t) + +#============= cloud_init_t ============== +# Let cloud-init finish first-boot setup on files Trident creates under /usr +# and unlabeled paths (before relabeling completes). +allow cloud_init_t unlabeled_t:dir { add_name getattr remove_name search write }; +allow cloud_init_t unlabeled_t:file { create getattr ioctl open read rename write }; +allow cloud_init_t usr_t:dir { add_name create remove_name write }; + +files_exec_usr_files(cloud_init_t) +files_manage_usr_files(cloud_init_t) + +#============= udev_t ============== +# Allow udev to use cloud-init file descriptors and FIFOs during device +# events triggered by Trident storage changes. +allow udev_t cloud_init_t:fd use; +allow udev_t cloud_init_t:fifo_file { append write getattr }; diff --git a/packaging/selinux-policy-trident/trident.te b/packaging/selinux-policy-trident/trident.te index 31996eda6..8649d9b89 100644 --- a/packaging/selinux-policy-trident/trident.te +++ b/packaging/selinux-policy-trident/trident.te @@ -556,17 +556,8 @@ allow trident_t var_run_t:sock_file write; allow trident_t var_spool_t:dir relabelto; allow trident_t wtmp_t:file relabelto; -# Inspect and update cloud-init state during first-boot provisioning. -optional_policy(` - require { - type cloud_init_exec_t; - type cloud_init_state_t; - } - allow trident_t cloud_init_exec_t:file getattr; - allow trident_t cloud_init_state_t:dir { list_dir_perms relabelto }; - allow trident_t cloud_init_state_t:lnk_file read_lnk_file_perms; - allow trident_t cloud_init_state_t:file getattr; -') +# NOTE: cloud-init policies have been moved to the trident-cloud-init SELinux +# module (packaging/selinux-policy-trident-cloud-init/). # Optional policies for types that may not exist on all images. # Trident encounters these files/dirs during OS provisioning and relabeling. @@ -680,13 +671,7 @@ systemd_read_user_runtime_units_files(trident_t) systemd_dbus_chat_logind(trident_t) systemd_read_user_unit_files(trident_t) -# Optional read access to cloud init state -optional_policy(` - require { - type cloud_init_t; - } - ps_process_pattern(trident_t, cloud_init_t) # equivalent to cloud_init_read_state(trident_t) -') +# NOTE: cloud-init process state reading moved to trident-cloud-init SELinux module. ########################################### # File System Operations @@ -944,18 +929,7 @@ optional_policy(` # SELinux module (packaging/selinux-policy-trident-raid/). #============= cloud_init_t ============== -# Let cloud-init finish first-boot setup on files Trident creates under /usr and unlabeled paths. -optional_policy(` - require { - type cloud_init_t; - } - allow cloud_init_t unlabeled_t:dir { add_name getattr remove_name search write }; - allow cloud_init_t unlabeled_t:file { create getattr ioctl open read rename write }; - allow cloud_init_t usr_t:dir { add_name create remove_name write }; - - files_exec_usr_files(cloud_init_t) - files_manage_usr_files(cloud_init_t) -') +# NOTE: cloud_init_t policies moved to trident-cloud-init SELinux module. #============= fsadm_t ============== # Allow mkfs/fsadm helpers spawned by Trident to manage EFI variables and loop-backed extension images. @@ -1031,13 +1005,7 @@ allow systemd_generator_t home_root_t:dir read; #============= udev_t ============== # Allow udev helpers triggered by Trident storage changes to inspect provisioning state and extension images. -optional_policy(` - require { - type cloud_init_t; - } - allow udev_t cloud_init_t:fd use; - allow udev_t cloud_init_t:fifo_file { append write getattr }; -') +# NOTE: cloud_init_t udev permissions moved to trident-cloud-init SELinux module. allow udev_t lvm_t:process { noatsecure rlimitinh siginh }; allow udev_t unlabeled_t:file getattr; From c36fd39073cbb6d585d9281552c1a77c19ace1b7 Mon Sep 17 00:00:00 2001 From: bfjelds Date: Wed, 13 May 2026 10:19:31 -0700 Subject: [PATCH 59/59] security: narrow and clean up SELinux policies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove unnecessary 'execute execute_no_trans' from chronyd, gpg-agent, logrotate, sudo, and kadmind — trident never executes these, it only inspects them during filesystem relabeling. Narrowed to getattr/read/map. - Remove miscfiles_read_man_pages — audit2allow artifact, trident does not read man pages. - Remove xkb_var_lib_t — audit2allow artifact, trident does not configure keyboard layouts. - Move tcsd_var_lib_t to trident-encryption module (TPM-related). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../trident-encryption.te | 9 +++++ packaging/selinux-policy-trident/trident.te | 37 ++++++++----------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/packaging/selinux-policy-trident-encryption/trident-encryption.te b/packaging/selinux-policy-trident-encryption/trident-encryption.te index 665a6d6e5..c6d0cf247 100644 --- a/packaging/selinux-policy-trident-encryption/trident-encryption.te +++ b/packaging/selinux-policy-trident-encryption/trident-encryption.te @@ -45,3 +45,12 @@ allow lvm_t tmp_t:file { getattr ioctl open read }; # Record PCR phase state in tmpfs while measuring encrypted boot progress. allow systemd_pcrphase_t tmpfs_t:dir { getattr open read search }; allow systemd_pcrphase_t tmpfs_t:file { getattr lock open setattr write }; + +#============= tcsd (TPM daemon) ============== +# Manage TPM daemon state directories during provisioning. +optional_policy(` + require { + type tcsd_var_lib_t; + } + allow trident_t tcsd_var_lib_t:dir { manage_dir_perms relabelto }; +') diff --git a/packaging/selinux-policy-trident/trident.te b/packaging/selinux-policy-trident/trident.te index 8649d9b89..2496d485c 100644 --- a/packaging/selinux-policy-trident/trident.te +++ b/packaging/selinux-policy-trident/trident.te @@ -602,12 +602,13 @@ auth_exec_pam(trident_t) auth_login_entry_type(trident_t) auth_read_lastlog(trident_t) auth_read_login_records(trident_t) +# Inspect GPG agent binary and secrets during filesystem relabeling. optional_policy(` require { type gpg_agent_exec_t; type gpg_secret_t; } - allow trident_t gpg_agent_exec_t:file { getattr open read execute entrypoint map }; + allow trident_t gpg_agent_exec_t:file { getattr open read map }; allow trident_t gpg_secret_t:dir list_dir_perms; allow trident_t gpg_secret_t:file read_file_perms; allow trident_t gpg_secret_t:lnk_file read_lnk_file_perms; @@ -625,13 +626,14 @@ userdom_relabelto_user_home_dirs(trident_t) ########################################### # Start helpers and inspect daemon state while Trident configures host services. # NOTE: bootloader_exec moved to trident-grub SELinux module. +# Inspect chronyd binary and config during filesystem relabeling. optional_policy(` require { type chronyd_exec_t; type chronyd_etc_t; type chronyd_keys_t; } - allow trident_t chronyd_exec_t:file { getattr open read execute execute_no_trans map }; + allow trident_t chronyd_exec_t:file { getattr open read map }; allow trident_t chronyd_etc_t:dir list_dir_perms; allow trident_t chronyd_etc_t:file read_file_perms; allow trident_t chronyd_keys_t:file read_file_perms; @@ -656,11 +658,12 @@ domain_read_all_domains_state(trident_t) hostname_exec(trident_t) init_domtrans(trident_t) init_rw_stream_sockets(trident_t) +# Inspect logrotate binary during filesystem relabeling. optional_policy(` require { type logrotate_exec_t; } - allow trident_t logrotate_exec_t:file { getattr open read execute execute_no_trans map }; + allow trident_t logrotate_exec_t:file { getattr open read map }; ') ssh_domtrans(trident_t) ssh_domtrans_keygen(trident_t) @@ -847,23 +850,25 @@ udev_read_state(trident_t) # System Command Execution ########################################### # Execute core host utilities in place during provisioning and customization workflows. +# Inspect sudo binary during filesystem relabeling. optional_policy(` require { type sudo_exec_t; } - allow trident_t sudo_exec_t:file { getattr open read execute execute_no_trans map }; + allow trident_t sudo_exec_t:file { getattr open read map }; ') corecmd_manage_bin_files(trident_t) corecmd_bin_entry_type(trident_t) corecmd_shell_entry_type(trident_t) corecmd_search_bin(trident_t) corecmd_exec_bin(trident_t) +# Inspect kerberos binary and config during filesystem relabeling. optional_policy(` require { type kadmind_exec_t; type krb5_conf_t; } - allow trident_t kadmind_exec_t:file { getattr open read execute execute_no_trans map }; + allow trident_t kadmind_exec_t:file { getattr open read map }; allow trident_t krb5_conf_t:dir list_dir_perms; allow trident_t krb5_conf_t:file read_file_perms; ') @@ -876,12 +881,7 @@ optional_policy(` } allow trident_t uuidd_var_lib_t:dir manage_dir_perms; ') -optional_policy(` - require { - type tcsd_var_lib_t; - } - allow trident_t tcsd_var_lib_t:dir { manage_dir_perms relabelto }; -') +# NOTE: tcsd_var_lib_t moved to trident-encryption SELinux module (TPM-related). ########################################### # Logging and Monitoring @@ -902,23 +902,16 @@ logging_manage_generic_logs(trident_t) optional_policy(` miscfiles_read_generic_tls_privkey(trident_t) ') -optional_policy(` - miscfiles_read_man_pages(trident_t) -') +# NOTE: miscfiles_read_man_pages removed — audit2allow artifact, trident +# does not read man pages. optional_policy(` miscfiles_read_localization(trident_t) ') optional_policy(` miscfiles_read_generic_certs(trident_t) ') -optional_policy(` - require { - type xkb_var_lib_t; - } - allow trident_t xkb_var_lib_t:dir list_dir_perms; - allow trident_t xkb_var_lib_t:file read_file_perms; - allow trident_t xkb_var_lib_t:lnk_file read_lnk_file_perms; -') +# NOTE: xkb_var_lib_t removed — audit2allow artifact, trident does not +# configure keyboard layouts. #################### #