From a5058e955d90cc968ba15bbae320fb17ef4a3d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Fri, 19 Jun 2026 19:04:20 +0800 Subject: [PATCH] test: guard ecstore object api boundaries (#3619) --- docs/architecture/migration-progress.md | 31 +++++++--- scripts/check_architecture_migration_rules.sh | 60 +++++++++++++++++++ 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index 140506080..190224d4c 100644 --- a/docs/architecture/migration-progress.md +++ b/docs/architecture/migration-progress.md @@ -5,17 +5,16 @@ 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-ecstore-object-api-alias-prune` -- Baseline: stacked after `rustfs/rustfs#3614` - (`3740e65246aed8c8ee9685ed0234997c7d54e1b5`). +- Branch: `overtrue/arch-ecstore-object-boundary-guards` +- Baseline: latest `main` after `rustfs/rustfs#3616` + (`8d91e2116f53fabc5f8a12a7cc48eb9d72cfcf10`). - PR type for this branch: `consumer-migration` - Runtime behavior changes: none. -- Rust code changes: remove unused public `rustfs-storage-api` passthrough - aliases from ECStore `object_api` and bind the ECStore contract test directly - to the storage-api generic list/delete/walk contracts. -- CI/script changes: make the migration guard reject restoring ECStore - `object_api` storage-api passthrough aliases. -- Docs changes: record the API-066 ECStore object API alias prune slice. +- Rust code changes: none. +- CI/script changes: snapshot the exact remaining external + `rustfs_ecstore::object_api` compatibility aliases and reject new + object-api names outside the approved boundary surface. +- Docs changes: record the API-067 ECStore object API boundary guard slice. ## Phase 0 Tasks @@ -318,6 +317,20 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block downstream compile checks, migration and layer guards, formatting, diff hygiene, risk scan, full pre-commit, and three-expert review. +- [x] `API-067` Guard remaining external ECStore object API aliases. + - Completed slice: add a migration guard that snapshots the exact external + `storage_compat.rs` aliases still allowed to reference + `rustfs_ecstore::object_api::{GetObjectReader,ObjectInfo,ObjectOptions,PutObjReader}` + and rejects new object-api names in compatibility boundaries. + - Acceptance: all remaining external `object_api` references are deliberate + compatibility aliases in `storage_compat.rs` modules, future additions fail + the migration guard, and the API-066 passthrough alias cleanup stays + protected. + - Must preserve: no runtime code changes, all existing compatibility aliases, + object metadata shape, options, and reader/writer ownership. + - Verification: bash syntax check, migration and layer guards, formatting, + diff hygiene, full pre-commit, and three-expert review. + - [x] `TEST-PRTYPE-001` Check PR type enum consistency. - Acceptance: `./scripts/check_architecture_migration_rules.sh` parses the allowed PR types from [`crate-boundaries.md`](crate-boundaries.md) and fails diff --git a/scripts/check_architecture_migration_rules.sh b/scripts/check_architecture_migration_rules.sh index e7344da03..b09d4979c 100755 --- a/scripts/check_architecture_migration_rules.sh +++ b/scripts/check_architecture_migration_rules.sh @@ -59,6 +59,10 @@ STORE_API_LIST_HELPER_REEXPORTS_FILE="${TMP_DIR}/store_api_list_helper_reexports STORE_API_LIST_RESPONSE_REEXPORTS_FILE="${TMP_DIR}/store_api_list_response_reexports.txt" ECSTORE_OBJECT_API_LIST_ALIAS_INTERNAL_HITS_FILE="${TMP_DIR}/ecstore_object_api_list_alias_internal_hits.txt" ECSTORE_OBJECT_API_STORAGE_ALIAS_HITS_FILE="${TMP_DIR}/ecstore_object_api_storage_alias_hits.txt" +ECSTORE_OBJECT_API_EXTERNAL_ALIAS_EXPECTED_FILE="${TMP_DIR}/ecstore_object_api_external_alias_expected.txt" +ECSTORE_OBJECT_API_EXTERNAL_ALIAS_ACTUAL_FILE="${TMP_DIR}/ecstore_object_api_external_alias_actual.txt" +ECSTORE_OBJECT_API_EXTERNAL_ALIAS_DIFF_FILE="${TMP_DIR}/ecstore_object_api_external_alias_diff.txt" +ECSTORE_OBJECT_API_UNAPPROVED_NAME_HITS_FILE="${TMP_DIR}/ecstore_object_api_unapproved_name_hits.txt" STORE_API_DELETE_DTO_REEXPORTS_FILE="${TMP_DIR}/store_api_delete_dto_reexports.txt" STORE_API_DELETE_DTO_INTERNAL_HITS_FILE="${TMP_DIR}/store_api_delete_dto_internal_hits.txt" STORE_API_LIFECYCLE_HELPER_DEFINITION_HITS_FILE="${TMP_DIR}/store_api_lifecycle_helper_definition_hits.txt" @@ -525,6 +529,62 @@ if [[ -s "$ECSTORE_OBJECT_API_STORAGE_ALIAS_HITS_FILE" ]]; then report_failure "ECStore object_api must not re-export storage-api passthrough aliases: $(paste -sd '; ' "$ECSTORE_OBJECT_API_STORAGE_ALIAS_HITS_FILE")" fi +cat >"$ECSTORE_OBJECT_API_EXTERNAL_ALIAS_EXPECTED_FILE" <<'EOF' +crates/heal/src/heal/storage_compat.rs:HealObjectInfo=ObjectInfo +crates/heal/src/heal/storage_compat.rs:HealObjectOptions=ObjectOptions +crates/heal/src/heal/storage_compat.rs:HealPutObjReader=PutObjReader +crates/iam/src/storage_compat.rs:IamConfigObjectInfo=ObjectInfo +crates/iam/src/storage_compat.rs:IamConfigObjectOptions=ObjectOptions +crates/iam/src/store/storage_compat.rs:IamObjectInfo=ObjectInfo +crates/iam/src/store/storage_compat.rs:IamObjectOptions=ObjectOptions +crates/notify/src/storage_compat.rs:EcstoreObjectInfo=ObjectInfo +crates/protocols/src/swift/storage_compat.rs:SwiftGetObjectReader=GetObjectReader +crates/protocols/src/swift/storage_compat.rs:SwiftObjectInfo=ObjectInfo +crates/protocols/src/swift/storage_compat.rs:SwiftObjectOptions=ObjectOptions +crates/protocols/src/swift/storage_compat.rs:SwiftPutObjReader=PutObjReader +crates/s3select-api/src/storage_compat.rs:SelectGetObjectReader=GetObjectReader +crates/s3select-api/src/storage_compat.rs:SelectObjectInfo=ObjectInfo +crates/s3select-api/src/storage_compat.rs:SelectObjectOptions=ObjectOptions +crates/scanner/src/storage_compat.rs:ScannerGetObjectReader=GetObjectReader +crates/scanner/src/storage_compat.rs:ScannerObjectInfo=ObjectInfo +crates/scanner/src/storage_compat.rs:ScannerObjectOptions=ObjectOptions +crates/scanner/src/storage_compat.rs:ScannerPutObjReader=PutObjReader +rustfs/src/storage/storage_compat.rs:GetObjectReader=GetObjectReader +rustfs/src/storage/storage_compat.rs:ObjectInfo=ObjectInfo +rustfs/src/storage/storage_compat.rs:ObjectOptions=ObjectOptions +rustfs/src/storage/storage_compat.rs:PutObjReader=PutObjReader +EOF + +( + cd "$ROOT_DIR" + find rustfs/src crates -type f -name 'storage_compat.rs' -print0 | + xargs -0 perl -ne ' + if (/^\s*(?:(?:pub(?:\([^)]*\))?)\s+)?type\s+([A-Za-z0-9_]+)\s*=\s*rustfs_ecstore::object_api::(GetObjectReader|ObjectInfo|ObjectOptions|PutObjReader)\s*;/) { + print "$ARGV:$1=$2\n"; + } + ' | sort +) >"$ECSTORE_OBJECT_API_EXTERNAL_ALIAS_ACTUAL_FILE" + +if ! diff -u "$ECSTORE_OBJECT_API_EXTERNAL_ALIAS_EXPECTED_FILE" "$ECSTORE_OBJECT_API_EXTERNAL_ALIAS_ACTUAL_FILE" >"$ECSTORE_OBJECT_API_EXTERNAL_ALIAS_DIFF_FILE"; then + report_failure "external ECStore object_api compatibility aliases changed without migration-plan approval: $(paste -sd '; ' "$ECSTORE_OBJECT_API_EXTERNAL_ALIAS_DIFF_FILE")" +fi + +( + cd "$ROOT_DIR" + find rustfs/src crates -type f -name 'storage_compat.rs' -print0 | + xargs -0 perl -ne ' + while (/rustfs_ecstore::object_api::([A-Za-z0-9_]+)/g) { + my $name = $1; + next if $name =~ /^(?:GetObjectReader|ObjectInfo|ObjectOptions|PutObjReader)$/; + print "$ARGV:$.:rustfs_ecstore::object_api::$name\n"; + } + ' | sort +) >"$ECSTORE_OBJECT_API_UNAPPROVED_NAME_HITS_FILE" + +if [[ -s "$ECSTORE_OBJECT_API_UNAPPROVED_NAME_HITS_FILE" ]]; then + report_failure "external storage compatibility boundaries must not expose new ECStore object_api names: $(paste -sd '; ' "$ECSTORE_OBJECT_API_UNAPPROVED_NAME_HITS_FILE")" +fi + ( cd "$ROOT_DIR" rg -n --no-heading 'rustfs_ecstore::store_api(?:::\{[^}]*\b(?:ObjectIO|ObjectOperations|ListOperations|MultipartOperations|HealOperations|NamespaceLocking)\b|::(?:ObjectIO|ObjectOperations|ListOperations|MultipartOperations|HealOperations|NamespaceLocking)\b)' \