mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-29 08:27:06 +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 {
|
impl From<rustfs_policy::error::Error> for Error {
|
||||||
fn from(e: rustfs_policy::error::Error) -> Self {
|
fn from(e: rustfs_policy::error::Error) -> Self {
|
||||||
match e {
|
match e {
|
||||||
@@ -437,4 +447,50 @@ mod tests {
|
|||||||
assert_eq!(error.to_string(), expected_message);
|
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