diff --git a/crates/ecstore/src/bucket/utils.rs b/crates/ecstore/src/bucket/utils.rs index dced6a0a1..b0da2ab44 100644 --- a/crates/ecstore/src/bucket/utils.rs +++ b/crates/ecstore/src/bucket/utils.rs @@ -137,25 +137,9 @@ pub fn has_bad_path_component(path: &str) -> bool { i += 1; } - // Trim whitespace of segment - let mut segment_start = start; - let mut segment_end = i; - - while segment_start < segment_end && bytes[segment_start].is_ascii_whitespace() { - segment_start += 1; - } - while segment_end > segment_start && bytes[segment_end - 1].is_ascii_whitespace() { - segment_end -= 1; - } - - // Check for ".." or "." - match segment_end - segment_start { - 2 if segment_start + 1 < n && bytes[segment_start] == b'.' && bytes[segment_start + 1] == b'.' => { - return true; - } - 1 if bytes[segment_start] == b'.' => { - return true; - } + // Trim whitespace of segment and check for ".." or "." + match path[start..i].trim() { + "." | ".." => return true, _ => {} } @@ -436,6 +420,9 @@ mod tests { assert!(!is_valid_object_prefix("prefix/./other")); assert!(!is_valid_object_prefix("a/../b/../c")); assert!(!is_valid_object_prefix("a/./b/./c")); + assert!(!is_valid_object_prefix("\x0b./object")); + assert!(!is_valid_object_prefix("prefix/\x0b../object")); + assert!(!is_valid_object_prefix("\x0b.\\\\object")); // Invalid cases - double slashes assert!(!is_valid_object_prefix("prefix//with//double//slashes")); diff --git a/crates/heal/src/heal/storage_compat.rs b/crates/heal/src/heal/storage_compat.rs index 7c7088586..265f1b9dc 100644 --- a/crates/heal/src/heal/storage_compat.rs +++ b/crates/heal/src/heal/storage_compat.rs @@ -13,8 +13,6 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{data_usage, disk, error, global, store, store_api}; } pub(crate) use self::ecstore::{ diff --git a/crates/iam/src/storage_compat.rs b/crates/iam/src/storage_compat.rs index cd80ec2bd..1317bcb26 100644 --- a/crates/iam/src/storage_compat.rs +++ b/crates/iam/src/storage_compat.rs @@ -13,7 +13,5 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{config, error, global, notification_sys, store}; } diff --git a/crates/notify/src/storage_compat.rs b/crates/notify/src/storage_compat.rs index 508075f54..573e9df05 100644 --- a/crates/notify/src/storage_compat.rs +++ b/crates/notify/src/storage_compat.rs @@ -13,8 +13,6 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{config, global, store_api}; } diff --git a/crates/obs/src/storage_compat.rs b/crates/obs/src/storage_compat.rs index d9f4782a4..7e2ff918c 100644 --- a/crates/obs/src/storage_compat.rs +++ b/crates/obs/src/storage_compat.rs @@ -13,7 +13,5 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{bucket, data_usage, global, pools, resolve_object_store_handle}; } diff --git a/crates/protocols/src/swift/storage_compat.rs b/crates/protocols/src/swift/storage_compat.rs index cb9c345e2..c71fb6fe3 100644 --- a/crates/protocols/src/swift/storage_compat.rs +++ b/crates/protocols/src/swift/storage_compat.rs @@ -13,8 +13,6 @@ // limitations under the License. mod ecstore { - #![allow(unused_imports)] - pub(super) use rustfs_ecstore::{bucket, error, resolve_object_store_handle, store, store_api}; } use self::ecstore::{ diff --git a/crates/s3select-api/src/storage_compat.rs b/crates/s3select-api/src/storage_compat.rs index d0a4acb82..c7a591414 100644 --- a/crates/s3select-api/src/storage_compat.rs +++ b/crates/s3select-api/src/storage_compat.rs @@ -13,8 +13,6 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{error, resolve_object_store_handle, set_disk, store, store_api}; } diff --git a/crates/scanner/src/storage_compat.rs b/crates/scanner/src/storage_compat.rs index e4a3d08ff..aaf2302ab 100644 --- a/crates/scanner/src/storage_compat.rs +++ b/crates/scanner/src/storage_compat.rs @@ -14,8 +14,6 @@ use http::HeaderMap; pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{ bucket, cache_value, config, data_usage, disk, error, global, pools, resolve_object_store_handle, set_disk, store, store_api, store_utils, diff --git a/crates/scanner/tests/common/storage_compat.rs b/crates/scanner/tests/common/storage_compat.rs index f33da8e08..65737d49a 100644 --- a/crates/scanner/tests/common/storage_compat.rs +++ b/crates/scanner/tests/common/storage_compat.rs @@ -13,7 +13,5 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{bucket, client, disk, endpoints, global, pools, store, tier}; } diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index a9d90981b..41abe4079 100644 --- a/docs/architecture/migration-progress.md +++ b/docs/architecture/migration-progress.md @@ -5,18 +5,18 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block ## Current Context - Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660) -- Branch: `overtrue/arch-remaining-storage-compat-exports` -- Baseline: `rustfs/rustfs#3576` head - `8255bd68539dc3c8cfc07a0ceb783ead67a02453`. +- Branch: `overtrue/arch-compat-reexport-prune` +- Baseline: `origin/main` after `rustfs/rustfs#3578` + (`f3fcdd4ba26181e3fe5d3afb6d6f5510bb9ad186`). - PR type for this branch: `consumer-migration` - Runtime behavior changes: no migration behavior change expected. -- Rust code changes: narrow remaining scanner, heal, Swift, and IAM store - ECStore compatibility boundary modules from direct ECStore imports to explicit - local `ecstore` re-export surfaces. ECStore-owned definitions and runtime - behavior stay in ECStore. -- CI/script changes: none. -- Docs changes: record the remaining compatibility export surface cleanup - slice. +- Rust code changes: prune unused ECStore compatibility re-export allowances + from production and fuzz compatibility boundaries, keep target-specific test + harness exceptions explicit, and gate test-only RustFS storage compatibility + re-exports with `cfg(test)`. +- CI/script changes: add a migration guard rejecting production + `storage_compat.rs` unused-import allows. +- Docs changes: record the compatibility re-export pruning slice. ## Phase 0 Tasks @@ -40,7 +40,9 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block public storage-api re-export coverage, ECStore compatibility-test coverage, and a production-source guard against reintroducing the removed `StorageAPI` aggregate facade identifier; add a source guard that rejects - direct `rustfs_ecstore` imports outside compatibility boundary modules. + direct `rustfs_ecstore` imports outside compatibility boundary modules; add + a guard that rejects production compatibility boundaries hiding unused + ECStore re-exports. - Acceptance: architecture migration rules fail if the public storage-api contract re-export surface drifts or if ECStore compile-time compatibility tests for the remaining storage-admin and namespace-lock contracts are @@ -963,6 +965,28 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block migration/layer guards, formatting check, diff hygiene, direct import scan, risk scan, full pre-commit, and required three-expert review passed. +- [x] `API-035` Prune compatibility re-export allowances. + - Current branch: `overtrue/arch-compat-reexport-prune`. + - Current slice: remove unused-import allowances from production and fuzz + ECStore compatibility boundary modules, keep target-specific test harness + exceptions explicit, gate test-only RustFS storage compatibility re-exports + with `cfg(test)`, and add a migration rule preventing production + compatibility boundaries from hiding unused ECStore re-exports. + - Acceptance: production and fuzz `storage_compat.rs` modules compile without + unused-import allows, test-only compatibility exceptions remain scoped to + harnesses with target-specific compile needs, and migration rules reject + reintroducing broad unused-import allowances in production compatibility + boundaries. + - Must preserve: all ECStore-owned concrete types and runtime behavior, + startup/storage/admin/app/Swift/scanner/heal/IAM/notify/obs/S3 Select + import paths, test harness behavior, and fuzz target behavior. + - Risk defense: this slice changes only compatibility boundary re-export + hygiene and migration guard coverage; it does not move definitions, alter + runtime control flow, mutate metadata formats, or change storage behavior. + - Verification: focused compile checks, fuzz manifest compile, migration and + layer guards, formatting check, diff hygiene, risk scan, full pre-commit, + and required three-expert review passed. + ## Phase 8 Background Controller Tasks - [x] `BGC-001` Inventory background services. @@ -1239,9 +1263,9 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block | Expert | Status | Notes | |---|---|---| -| Quality/architecture | passed | Scanner, heal, Swift, and IAM store now keep direct ECStore references inside local compatibility boundary modules with existing local semantic aliases preserved; guard coverage rejects new bypasses. | -| Migration preservation | passed | ECStore remains the owner of backing types and behavior; scanner, heal, Swift, and IAM runtime semantics are unchanged. | -| Testing/verification | passed | Focused scanner/heal/IAM compile, Swift feature compile, guards, formatting check, diff hygiene, risk scan, and full `make pre-commit` passed. | +| Quality/architecture | passed | Production compatibility boundaries no longer hide unused ECStore re-exports behind broad unused-import allows; target-specific test exceptions remain scoped. | +| Migration preservation | passed | ECStore remains the owner of backing types and behavior; this slice only changes compatibility-boundary hygiene and guard coverage. | +| Testing/verification | passed | Focused compile checks, fuzz manifest compile, guards, formatting, diff hygiene, risk scan, and full `make pre-commit` passed. | ## Verification Notes @@ -1250,6 +1274,9 @@ Passed before push: - `cargo check --tests -p rustfs-scanner -p rustfs-heal -p rustfs-iam`: passed. - `cargo check --tests -p rustfs-protocols --features swift`: passed. +- `cargo check --tests -p rustfs -p rustfs-scanner -p rustfs-heal -p rustfs-iam -p rustfs-notify -p rustfs-obs -p rustfs-s3select-api -p e2e_test`: + passed. +- `cargo check --manifest-path fuzz/Cargo.toml --bins`: passed. - `rg -n 'rustfs_ecstore' crates/scanner/src crates/heal/src crates/protocols/src/swift crates/iam/src/store --glob '*.rs'`: remaining matches are deliberate compatibility boundary definitions. - `./scripts/check_architecture_migration_rules.sh`: passed. diff --git a/fuzz/fuzz_targets/storage_compat.rs b/fuzz/fuzz_targets/storage_compat.rs index f1cc4063d..3d19f6c4a 100644 --- a/fuzz/fuzz_targets/storage_compat.rs +++ b/fuzz/fuzz_targets/storage_compat.rs @@ -13,7 +13,5 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::bucket; } diff --git a/rustfs/src/admin/storage_compat.rs b/rustfs/src/admin/storage_compat.rs index 32da669e2..661a9213f 100644 --- a/rustfs/src/admin/storage_compat.rs +++ b/rustfs/src/admin/storage_compat.rs @@ -13,8 +13,6 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{ bucket, client, config, data_usage, disk, endpoints, error, global, metrics_realtime, notification_sys, rebalance, rpc, store, store_utils, tier, diff --git a/rustfs/src/app/storage_compat.rs b/rustfs/src/app/storage_compat.rs index eae74e7e5..fafbe52ae 100644 --- a/rustfs/src/app/storage_compat.rs +++ b/rustfs/src/app/storage_compat.rs @@ -13,8 +13,6 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{ admin_server_info, bucket, client, compress, config, data_usage, disk, endpoints, error, global, new_object_layer_fn, notification_sys, pools, rio, set_disk, set_object_store_resolver, store, tier, diff --git a/rustfs/src/storage/storage_compat.rs b/rustfs/src/storage/storage_compat.rs index ee9469fb2..916038fe8 100644 --- a/rustfs/src/storage/storage_compat.rs +++ b/rustfs/src/storage/storage_compat.rs @@ -13,10 +13,11 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{ - admin_server_info, bucket, client, config, disk, error, get_global_lock_client, global, metrics_realtime, + admin_server_info, bucket, client, disk, error, get_global_lock_client, global, metrics_realtime, resolve_object_store_handle, rio, rpc, set_disk, store, store_api, }; + + #[cfg(test)] + pub(crate) use rustfs_ecstore::config; } diff --git a/rustfs/src/storage_compat.rs b/rustfs/src/storage_compat.rs index bac20d8e5..0cb6ecc42 100644 --- a/rustfs/src/storage_compat.rs +++ b/rustfs/src/storage_compat.rs @@ -13,10 +13,11 @@ // limitations under the License. pub(crate) mod ecstore { - #![allow(unused_imports)] - pub(crate) use rustfs_ecstore::{ - bucket, config, data_usage, disk, disks_layout, endpoints, error, event_notification, global, notification_sys, pools, - resolve_object_store_handle, rpc, set_disk, set_global_endpoints, store, update_erasure_type, + bucket, config, disk, endpoints, error, event_notification, global, notification_sys, resolve_object_store_handle, rpc, + set_disk, set_global_endpoints, store, update_erasure_type, }; + + #[cfg(test)] + pub(crate) use rustfs_ecstore::disks_layout; } diff --git a/scripts/check_architecture_migration_rules.sh b/scripts/check_architecture_migration_rules.sh index b53d8a6df..57fd3fb1d 100755 --- a/scripts/check_architecture_migration_rules.sh +++ b/scripts/check_architecture_migration_rules.sh @@ -61,6 +61,7 @@ STORE_API_EXTERNAL_LIST_CONSUMER_HITS_FILE="${TMP_DIR}/store_api_external_list_c STORE_API_EXTERNAL_OPERATION_CONSUMER_HITS_FILE="${TMP_DIR}/store_api_external_operation_consumer_hits.txt" STORE_API_OBJECT_OPERATION_LOCAL_METHOD_HITS_FILE="${TMP_DIR}/store_api_object_operation_local_method_hits.txt" DIRECT_ECSTORE_IMPORT_HITS_FILE="${TMP_DIR}/direct_ecstore_import_hits.txt" +PRODUCTION_UNUSED_COMPAT_ALLOW_HITS_FILE="${TMP_DIR}/production_unused_compat_allow_hits.txt" awk ' /^## PR Types$/ { @@ -334,6 +335,19 @@ if [[ -s "$DIRECT_ECSTORE_IMPORT_HITS_FILE" ]]; then report_failure "direct rustfs_ecstore imports outside compatibility boundaries are forbidden: $(paste -sd '; ' "$DIRECT_ECSTORE_IMPORT_HITS_FILE")" fi +( + cd "$ROOT_DIR" + rg -n --no-heading '#!\[allow\(unused_imports\)\]' \ + rustfs/src crates/*/src fuzz/fuzz_targets \ + --glob '*storage_compat.rs' \ + --glob '!crates/ecstore/**' \ + --glob '!crates/e2e_test/**' || true +) >"$PRODUCTION_UNUSED_COMPAT_ALLOW_HITS_FILE" + +if [[ -s "$PRODUCTION_UNUSED_COMPAT_ALLOW_HITS_FILE" ]]; then + report_failure "production storage compatibility boundaries must not hide unused ECStore re-exports: $(paste -sd '; ' "$PRODUCTION_UNUSED_COMPAT_ALLOW_HITS_FILE")" +fi + ( cd "$ROOT_DIR" rg -n --no-heading 'async fn (get_object_reader|put_object|get_object_info|verify_object_integrity|copy_object|delete_object_version|delete_object|delete_objects|put_object_metadata|get_object_tags|put_object_tags|delete_object_tags|add_partial|transition_object|restore_transitioned_object|list_multipart_uploads|new_multipart_upload|copy_object_part|put_object_part|get_multipart_info|list_object_parts|abort_multipart_upload|complete_multipart_upload|heal_format|heal_bucket|heal_object|get_pool_and_set|check_abandoned_parts|new_ns_lock)\b' \