Merge commit from fork

docs/testing/security-regressions.md requires every fixed advisory to map to a
named, greppable regression test. Rename the tests added with the fixes to carry
their advisory id so `rg -i ghsa` finds them, and add the four rows to the
advisory -> test map.

Adds the FTPS MKD regression test that was missing. It primes the dummy backend
with a successful create_bucket, so the assertion distinguishes "denied at the
authorization boundary" from "backend refused" — without the queued success an
unconfigured create_bucket fails on its own and the test would pass even with
the authorization check removed. Verified it fails when the check is reverted.

DummyBackend gains a Debug impl (FtpsDriver's trait bounds require it) and a
queue_create_bucket_ok helper.

Records in the CI-execution map why ghsa_g3vq_* runs in the default pass despite
sitting behind the ftps feature: the rustfs crate defaults to ["ftps", "webdav"]
and cargo unifies features across the workspace build, so the test executes
there even though `cargo test -p rustfs-protocols` alone would skip it.
This commit is contained in:
Zhengchao An
2026-07-26 07:10:50 +08:00
committed by GitHub
parent 92f83bfe15
commit 7f19e9a465
6 changed files with 75 additions and 9 deletions
+31
View File
@@ -898,6 +898,37 @@ mod tests {
use super::parse_s3_path;
use rustfs_utils::path;
/// GHSA-g3vq-vv42-f647: MKD creates a bucket, so it must clear the
/// `s3:CreateBucket` authorization boundary before touching the backend.
/// The queued success is what makes this a real guard — an unqueued
/// create_bucket would fail on its own and the test would pass even if the
/// authorization check were removed again.
#[tokio::test]
async fn ghsa_g3vq_mkd_denied_before_reaching_backend() {
use super::FtpsDriver;
use crate::common::dummy_storage::DummyBackend;
use crate::common::gateway::with_test_auth_override;
use crate::common::session::{Protocol, test_session};
use unftp_core::storage::StorageBackend as _;
let backend = DummyBackend::new();
backend.queue_create_bucket_ok();
let driver = FtpsDriver::new(backend);
let user = super::super::server::FtpsUser {
username: "denied-user".to_string(),
name: None,
session_context: test_session(Protocol::Ftps),
};
let result = with_test_auth_override(|_, _, _| false, driver.mkd(&user, "/denied-bucket")).await;
assert!(
result.is_err(),
"MKD must fail closed when authorization denies s3:CreateBucket, even though the backend was primed to succeed"
);
}
proptest::proptest! {
#[test]
fn parse_s3_path_never_leaks_control_bytes_or_traversal_in_ok_output(