diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9253a7d0d4..bee77802e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -255,6 +255,18 @@ jobs: env: PASEO_DESKTOP_SMOKE_ARTIFACT_DIR: ${{ runner.temp }}/desktop-smoke/userns + - name: Smoke installed RPM with restricted user namespaces + if: ${{ runner.os == 'Linux' }} + run: | + sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=1 + sudo dpkg --remove paseo + # Ubuntu supplies the runtime libraries under Debian package names. + # RPM still performs the real payload installation and postinstall. + sudo rpm --install --nodeps packages/desktop/release/*.rpm + node packages/desktop/e2e/linux-artifact-smoke.js packages/desktop/release disabled --installed-only + env: + PASEO_DESKTOP_SMOKE_ARTIFACT_DIR: ${{ runner.temp }}/desktop-smoke/rpm + - name: Upload packaged smoke diagnostics uses: actions/upload-artifact@v4 if: ${{ !cancelled() && runner.os == 'Linux' }} diff --git a/docs/testing.md b/docs/testing.md index ec5626b209..933dcba740 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -114,7 +114,7 @@ The harness launches the packaged app with isolated user data and daemon state, - the renderer starts a fresh desktop-managed daemon through the normal startup bootstrap; - the bundled CLI can query that daemon and run a terminal command. -Pull-request CI runs the Linux x64 smoke under Xvfb when the cumulative PR diff selects desktop coverage. The Linux job is pinned to Ubuntu 24.04 and runs twice: with AppArmor user namespace restrictions enabled, then with user namespaces available. It installs the real `.deb`, launches the real AppImage via `--appimage-extract-and-run`, and launches the extracted tar archive. Each launch verifies the reported sandbox decision; enabled renderers must also have `NoNewPrivs: 1` and `Seccomp: 2` in `/proc`. The desktop release matrix retains its host-native smokes. Linux release builds stay on Ubuntu 22.04 to preserve their native-library baseline; the restricted-host regression runs on Ubuntu 24.04 in PR CI. +Pull-request CI runs the Linux x64 smoke under Xvfb when the cumulative PR diff selects desktop coverage. The Linux job is pinned to Ubuntu 24.04 and runs twice: with AppArmor user namespace restrictions enabled, then with user namespaces available. It installs the real `.deb`, launches the real AppImage via `--appimage-extract-and-run`, and launches the extracted tar archive. It also replaces the Debian installation with the generated RPM through `rpm --install --nodeps` and checks its sandboxed launch under restrictions. Ubuntu supplies the runtime libraries under Debian package names, so this verifies the RPM payload and postinstall rather than Fedora dependency resolution. Each launch verifies the reported sandbox decision; enabled renderers must also have `NoNewPrivs: 1` and `Seccomp: 2` in `/proc`. The desktop release matrix retains its host-native smokes. Linux release builds stay on Ubuntu 22.04 to preserve their native-library baseline; the restricted-host regression runs on Ubuntu 24.04 in PR CI. Never repair `chrome-sandbox` in the smoke harness. The old unpacked smoke set its mode to 4755 and concealed a broken package installer. Run installer tests as root and launch tests as an ordinary user: a root-run namespace probe does not reproduce Ubuntu's AppArmor policy for desktop users. Preserve both restricted and unrestricted cases; either one alone permits another sandbox regression. diff --git a/packages/desktop/e2e/linux-artifact-smoke.js b/packages/desktop/e2e/linux-artifact-smoke.js index 77bca8bb51..5a81bf07de 100644 --- a/packages/desktop/e2e/linux-artifact-smoke.js +++ b/packages/desktop/e2e/linux-artifact-smoke.js @@ -10,6 +10,7 @@ async function main() { const release = path.resolve(process.argv[2]); const portableSandbox = process.argv[3] === "enabled"; const artifactRoot = process.env.PASEO_DESKTOP_SMOKE_ARTIFACT_DIR; + const installedOnly = process.argv.includes("--installed-only"); const extracted = fs.mkdtempSync(path.join(os.tmpdir(), "paseo-linux-artifacts-")); const findArtifact = (suffix) => { const matches = fs.readdirSync(release).filter((file) => file.endsWith(suffix)); @@ -17,12 +18,13 @@ async function main() { return path.join(release, matches[0]); }; try { - process.env.PASEO_DESKTOP_SMOKE_ARTIFACT_DIR = path.join(artifactRoot, "deb"); + process.env.PASEO_DESKTOP_SMOKE_ARTIFACT_DIR = path.join(artifactRoot, "installed"); const helper = fs.statSync("/opt/Paseo/chrome-sandbox"); if (helper.uid !== 0 || (helper.mode & 0o7777) !== 0o4755) { - throw new Error("Installed .deb did not provide a root-owned 4755 helper"); + throw new Error("Installed native package did not provide a root-owned 4755 helper"); } await smokePackagedDesktopApp({ appPath: "/opt/Paseo", expectedSandbox: true }); + if (installedOnly) return; const appImage = findArtifact(".AppImage"); fs.chmodSync(appImage, 0o755);