fix(api): skip mode-bit tests when they cannot bind
ci / web (push) Successful in 1m5s
ci / rust (push) Successful in 1m56s
e2e / e2e (push) Failing after 7m5s

Four tests force a filesystem failure by freezing a directory to 0o555.
The CI container runs as root, mode bits do not constrain root, and the
rename those tests expect to fail succeeds — main has been red on
a_failed_rename_leaves_the_row_alone since the move-on-root-change work
landed, with nextest's fail-fast hiding the other three.

The guard probes the filesystem rather than the uid: what the tests
depend on is the refusal, and a container can hold CAP_DAC_OVERRIDE
without being uid 0.
This commit is contained in:
Miguel Palhas
2026-08-26 08:35:26 +01:00
parent 425d154d54
commit 656ca6c259
4 changed files with 63 additions and 0 deletions
+2
View File
@@ -12,6 +12,8 @@ mod metadata;
mod movies;
mod owners;
mod policies;
#[cfg(test)]
mod privilege;
mod reclassify;
mod relocate;
mod roots;
+4
View File
@@ -1944,6 +1944,10 @@ mod tests {
async fn a_failed_rename_leaves_the_row_alone() {
use std::os::unix::fs::PermissionsExt;
if !crate::privilege::mode_bits_bind().await {
crate::privilege::skipped_because_privileged("a_failed_rename_leaves_the_row_alone");
return;
}
let (_dir, state, base) = application().await;
let movie = add_movie(&base, 693_134, 1).await;
let id = movie["id"].as_i64().expect("id");
+36
View File
@@ -0,0 +1,36 @@
//! Whether mode bits actually constrain this process.
//!
//! Four tests force a filesystem failure by freezing a directory to `0o555`
//! and asserting the handler reports it. Mode bits do not constrain a
//! privileged user, so under `root` — which is what the CI container runs
//! as — the operation succeeds and the assertion fails for a reason that has
//! nothing to do with the code under test.
//!
//! The probe asks the filesystem rather than asking for the uid: what the
//! tests depend on is the refusal, not the identity, and a container can
//! hold `CAP_DAC_OVERRIDE` without being uid 0.
/// True when a read-only directory refuses a write to this process.
pub(crate) async fn mode_bits_bind() -> bool {
use std::os::unix::fs::PermissionsExt;
let probe = tempfile::tempdir().expect("probe root");
let frozen = probe.path().join("frozen");
tokio::fs::create_dir(&frozen).await.expect("probe folder");
tokio::fs::set_permissions(&frozen, std::fs::Permissions::from_mode(0o555))
.await
.expect("freeze the probe folder");
let refused = tokio::fs::write(frozen.join("probe"), b"x").await.is_err();
// `TempDir::drop` needs the write back to remove the tree
tokio::fs::set_permissions(&frozen, std::fs::Permissions::from_mode(0o755))
.await
.expect("thaw the probe folder");
refused
}
/// Announces a test that cannot run here, on stderr, which `nextest` prints
/// when the run is given `--no-capture` and swallows otherwise — the same
/// deal every other skipped case in a Rust suite gets.
pub(crate) fn skipped_because_privileged(test: &str) {
eprintln!("{test}: skipped — this process overrides mode bits, so the failure it forces cannot happen");
}
+21
View File
@@ -1048,6 +1048,13 @@ mod tests {
async fn one_folder_that_cannot_move_puts_the_others_back() {
use std::os::unix::fs::PermissionsExt;
if !crate::privilege::mode_bits_bind().await {
crate::privilege::skipped_because_privileged(
"one_folder_that_cannot_move_puts_the_others_back",
);
return;
}
let (_dir, state, base) = application().await;
let old = tempfile::tempdir().expect("old root");
let home = tempfile::tempdir().expect("home of the new path");
@@ -1125,6 +1132,13 @@ mod tests {
async fn a_new_root_that_already_existed_survives_a_failed_move() {
use std::os::unix::fs::PermissionsExt;
if !crate::privilege::mode_bits_bind().await {
crate::privilege::skipped_because_privileged(
"a_new_root_that_already_existed_survives_a_failed_move",
);
return;
}
let (_dir, state, base) = application().await;
let old = tempfile::tempdir().expect("old root");
let new = tempfile::tempdir().expect("new root, already there");
@@ -1393,6 +1407,13 @@ mod tests {
async fn a_failed_move_removes_every_level_it_created() {
use std::os::unix::fs::PermissionsExt;
if !crate::privilege::mode_bits_bind().await {
crate::privilege::skipped_because_privileged(
"a_failed_move_removes_every_level_it_created",
);
return;
}
let (_dir, state, base) = application().await;
let old = tempfile::tempdir().expect("old root");
let home = tempfile::tempdir().expect("home of the new path");