mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-29 16:37:07 +00:00
test(iam): pin the policy-to-iam error mapping and record the fold verdict (#6635)
Backlog#1845 step 8 conclusion. The plan called for folding iam::Error into a policy::Error #[from] wrapper and deleting the hand-written mapping. Measurement rejected the fold: the duplicated variants have ~220 construction/match sites (about 140 in production) across iam and the admin handlers - all auth-critical - and the alias route is blocked by the orphan rule (iam's From<IamStorageError> and io conversions cannot be implemented for a foreign type). Meanwhile the drift risk the fold targeted is already compiler-covered: the From match is exhaustive with no catch-all, so any new policy variant fails the build until mapped. What remains of the step, delivered: the six dead policy variants are gone (previous commit), the grouped lossy arm is down to the two variants actually produced, a doc comment on the From impl records the verdict with the evidence, and a new totality test constructs one representative of every policy::error::Error variant and asserts the conversion preserves the rendered message - so the mapping is now pinned loss-free in both directions the classifiers care about. Ref rustfs/backlog#1845
This commit is contained in:
@@ -186,6 +186,16 @@ impl From<Error> for IamStorageError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Deliberately a flat, exhaustive mapping rather than a wrapper variant
|
||||
/// (backlog#1845 step 8 verdict): folding iam::Error into a
|
||||
/// `Policy(Arc<policy::Error>)` wrapper would leave ~140 production
|
||||
/// construction/match sites across iam and the admin handlers to migrate in
|
||||
/// auth-critical code, and a type alias is blocked by the orphan rule (iam's
|
||||
/// `From<IamStorageError>` / io conversions cannot be implemented for a
|
||||
/// foreign type). The drift risk the fold aimed at is already covered by the
|
||||
/// compiler: this match has no catch-all, so any new policy variant fails the
|
||||
/// build here until mapped, and `policy_to_iam_mapping_preserves_messages`
|
||||
/// pins that every arm keeps the rendered message intact.
|
||||
impl From<rustfs_policy::error::Error> for Error {
|
||||
fn from(e: rustfs_policy::error::Error) -> Self {
|
||||
match e {
|
||||
@@ -437,4 +447,50 @@ mod tests {
|
||||
assert_eq!(error.to_string(), expected_message);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn policy_to_iam_mapping_preserves_messages() {
|
||||
use rustfs_policy::error::Error as PErr;
|
||||
// One representative per policy::error::Error variant. When a new
|
||||
// variant is added, the exhaustive From match breaks the build first;
|
||||
// extend this list in the same change so the message stays pinned.
|
||||
let representatives: Vec<PErr> = vec![
|
||||
PErr::PolicyError(rustfs_policy::policy::Error::NonResource),
|
||||
PErr::StringError("free-form".to_string()),
|
||||
PErr::NoSuchUser("u".to_string()),
|
||||
PErr::NoSuchAccount("a".to_string()),
|
||||
PErr::NoSuchServiceAccount("sa".to_string()),
|
||||
PErr::NoSuchTempAccount("ta".to_string()),
|
||||
PErr::NoSuchGroup("g".to_string()),
|
||||
PErr::NoSuchPolicy,
|
||||
PErr::PolicyInUse,
|
||||
PErr::GroupNotEmpty,
|
||||
PErr::InvalidArgument,
|
||||
PErr::IamSysNotInitialized,
|
||||
PErr::InvalidServiceType("svc".to_string()),
|
||||
PErr::InvalidAccessKeyLength,
|
||||
PErr::InvalidSecretKeyLength,
|
||||
PErr::ContainsReservedChars,
|
||||
PErr::GroupNameContainsReservedChars,
|
||||
PErr::IAMActionNotAllowed,
|
||||
PErr::NoSecretKeyWithAccessKey,
|
||||
PErr::NoAccessKeyWithSecretKey,
|
||||
PErr::PolicyTooLarge,
|
||||
PErr::Io(std::io::Error::other("io detail")),
|
||||
PErr::IamSysAlreadyInitialized,
|
||||
];
|
||||
|
||||
for policy_err in representatives {
|
||||
let rendered = policy_err.to_string();
|
||||
let iam_err: Error = policy_err.into();
|
||||
assert_eq!(iam_err.to_string(), rendered, "policy->iam conversion must preserve the rendered message");
|
||||
}
|
||||
|
||||
// The one #[from] payload variant: rendering is preserved end to end.
|
||||
let jwt_err =
|
||||
rustfs_policy::error::Error::from(jsonwebtoken::errors::Error::from(jsonwebtoken::errors::ErrorKind::InvalidToken));
|
||||
let rendered = jwt_err.to_string();
|
||||
let iam_err: Error = jwt_err.into();
|
||||
assert_eq!(iam_err.to_string(), rendered);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user