diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d0a5d9..f91cd72 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,8 +64,15 @@ jobs: run: dnf install -y gcc make curl - name: Install build deps (openSUSE) if: matrix.os == 'opensuse' - run: zypper install -y gcc make curl gzip tar xz bash + run: zypper install -y gcc make curl gzip tar xz + - name: Install Rust (container) + if: matrix.container != '' + shell: sh + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain $RUST_TOOLCHAIN --profile minimal + echo "$HOME/.cargo/bin" >> $GITHUB_PATH - uses: dtolnay/rust-toolchain@stable + if: matrix.container == '' with: toolchain: ${{ env.RUST_TOOLCHAIN }} - uses: Swatinem/rust-cache@v2 @@ -136,15 +143,17 @@ jobs: setup: "dnf install -y gcc make curl fuse-overlayfs fuse3 crun" - os: opensuse container: opensuse/tumbleweed:latest - setup: "zypper install -y gcc make curl fuse-overlayfs gzip tar xz bash crun" + setup: "zypper install -y gcc make curl fuse-overlayfs gzip tar xz crun" container: ${{ matrix.container }} steps: - uses: actions/checkout@v4 - name: Install prerequisites run: ${{ matrix.setup }} - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: ${{ env.RUST_TOOLCHAIN }} + - name: Install Rust + shell: sh + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain $RUST_TOOLCHAIN --profile minimal + echo "$HOME/.cargo/bin" >> $GITHUB_PATH - uses: Swatinem/rust-cache@v2 - name: Enable user namespaces run: sysctl -w kernel.unprivileged_userns_clone=1 || true diff --git a/crates/karapace-core/tests/integration.rs b/crates/karapace-core/tests/integration.rs index 70560fd..cb6bc7d 100644 --- a/crates/karapace-core/tests/integration.rs +++ b/crates/karapace-core/tests/integration.rs @@ -8,6 +8,15 @@ use std::path::Path; use std::sync::{Arc, Barrier}; use std::thread; +/// Skip test if running as root — root bypasses filesystem permission checks, +/// so read-only directory tests are meaningless in containers running as uid 0. +fn skip_if_root() -> bool { + #[allow(unsafe_code)] + unsafe { + libc::getuid() == 0 + } +} + fn write_manifest(dir: &Path, content: &str) -> std::path::PathBuf { let path = dir.join("karapace.toml"); fs::write(&path, content).unwrap(); @@ -1370,6 +1379,7 @@ fn gc_is_idempotent_after_partial_run() { // M6.2: Object read fails gracefully on permission denied #[test] fn object_get_fails_on_permission_denied() { + if skip_if_root() { return; } let store = tempfile::tempdir().unwrap(); let layout = StoreLayout::new(store.path()); layout.initialize().unwrap(); @@ -1391,6 +1401,7 @@ fn object_get_fails_on_permission_denied() { // M6.2: Metadata write fails gracefully on read-only store #[test] fn metadata_put_fails_on_read_only_dir() { + if skip_if_root() { return; } let store = tempfile::tempdir().unwrap(); let layout = StoreLayout::new(store.path()); layout.initialize().unwrap(); @@ -1594,6 +1605,7 @@ fn stale_running_marker_cleaned_on_engine_new() { #[test] fn build_on_readonly_objects_dir_returns_error() { + if skip_if_root() { return; } let store = tempfile::tempdir().unwrap(); let project = tempfile::tempdir().unwrap(); @@ -1618,6 +1630,7 @@ fn build_on_readonly_objects_dir_returns_error() { #[test] fn build_on_readonly_metadata_dir_returns_error() { + if skip_if_root() { return; } let store = tempfile::tempdir().unwrap(); let project = tempfile::tempdir().unwrap(); @@ -1640,6 +1653,7 @@ fn build_on_readonly_metadata_dir_returns_error() { #[test] fn commit_on_readonly_layers_dir_returns_error() { + if skip_if_root() { return; } let store = tempfile::tempdir().unwrap(); let project = tempfile::tempdir().unwrap(); let engine = Engine::new(store.path()); @@ -1678,6 +1692,7 @@ fn commit_on_readonly_layers_dir_returns_error() { #[test] fn write_failure_never_panics() { + if skip_if_root() { return; } let store = tempfile::tempdir().unwrap(); let layout = StoreLayout::new(store.path()); layout.initialize().unwrap(); @@ -2099,6 +2114,7 @@ backend = "mock" #[test] fn wal_write_fails_on_readonly_dir() { + if skip_if_root() { return; } let store = tempfile::tempdir().unwrap(); let layout = StoreLayout::new(store.path()); layout.initialize().unwrap(); @@ -2122,6 +2138,7 @@ fn wal_write_fails_on_readonly_dir() { #[test] fn build_fails_cleanly_when_wal_dir_is_readonly() { + if skip_if_root() { return; } let store = tempfile::tempdir().unwrap(); let project = tempfile::tempdir().unwrap();