mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-16 01:48:21 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 398d16f58c | |||
| 9e48c05493 |
@@ -40,7 +40,14 @@ impl ARN {
|
||||
|
||||
impl Display for ARN {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "arn:rustfs:{}:{}:{}:{}", self.arn_type, self.region, self.id, self.bucket)
|
||||
// The `minio` partition is deliberate: madmin-go's ParseARN
|
||||
// hard-rejects any other partition, so native mc/madmin tooling can
|
||||
// only decode remote-target ARNs minted in this form (backlog#1675
|
||||
// P1-7). Legacy `arn:rustfs:` ARNs persisted by older releases stay
|
||||
// readable via the FromStr whitelist below; runtime matching between
|
||||
// targets and replication rules is by full-string equality, so mixed
|
||||
// partitions coexist safely.
|
||||
write!(f, "arn:minio:{}:{}:{}:{}", self.arn_type, self.region, self.id, self.bucket)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +55,12 @@ impl FromStr for ARN {
|
||||
type Err = std::io::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if !s.starts_with("arn:rustfs:") {
|
||||
// Partition whitelist, not just an `arn:` check: `BucketTargetType::
|
||||
// from_str(...).unwrap_or_default()` below never fails, so this is
|
||||
// the only structural gate rejecting foreign ARNs. `arn:rustfs:` is
|
||||
// the legacy partition and must stay accepted forever (persisted
|
||||
// bucket-targets.json / replication configs from older releases).
|
||||
if !s.starts_with("arn:minio:") && !s.starts_with("arn:rustfs:") {
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid ARN format"));
|
||||
}
|
||||
|
||||
@@ -101,14 +113,50 @@ mod tests {
|
||||
}
|
||||
|
||||
/// RustFS commonly generates ARNs with an empty region:
|
||||
/// `arn:rustfs:replication::<deployment_id>:<bucket>`.
|
||||
/// `arn:minio:replication::<deployment_id>:<bucket>`.
|
||||
#[test]
|
||||
fn from_str_handles_empty_region_segment() {
|
||||
let parsed = ARN::from_str("arn:rustfs:replication::depl-123:bucket-a").expect("valid ARN must parse");
|
||||
let parsed = ARN::from_str("arn:minio:replication::depl-123:bucket-a").expect("valid ARN must parse");
|
||||
|
||||
assert_eq!(parsed.arn_type, BucketTargetType::ReplicationService);
|
||||
assert_eq!(parsed.region, "", "region segment is empty in this form");
|
||||
assert_eq!(parsed.id, "depl-123");
|
||||
assert_eq!(parsed.bucket, "bucket-a");
|
||||
}
|
||||
|
||||
/// madmin-go's `ParseARN` hard-rejects anything that does not start with
|
||||
/// `arn:minio:`, so generated ARNs must use the `minio` partition or the
|
||||
/// native mc/madmin tooling cannot decode remote-target listings.
|
||||
#[test]
|
||||
fn display_emits_minio_partition() {
|
||||
let arn = ARN::new(
|
||||
BucketTargetType::ReplicationService,
|
||||
"depl-123".to_string(),
|
||||
String::new(),
|
||||
"bucket-a".to_string(),
|
||||
);
|
||||
|
||||
assert_eq!(arn.to_string(), "arn:minio:replication::depl-123:bucket-a");
|
||||
}
|
||||
|
||||
/// Persisted bucket-targets.json files from older RustFS releases carry
|
||||
/// `arn:rustfs:` ARNs; the legacy partition must stay parseable forever.
|
||||
#[test]
|
||||
fn from_str_accepts_legacy_rustfs_partition() {
|
||||
let parsed = ARN::from_str("arn:rustfs:replication:us-east-1:depl-123:bucket-a").expect("legacy ARN must parse");
|
||||
|
||||
assert_eq!(parsed.arn_type, BucketTargetType::ReplicationService);
|
||||
assert_eq!(parsed.region, "us-east-1");
|
||||
assert_eq!(parsed.id, "depl-123");
|
||||
assert_eq!(parsed.bucket, "bucket-a");
|
||||
}
|
||||
|
||||
/// The partition whitelist is the only structural gate: `BucketTargetType::
|
||||
/// from_str(...).unwrap_or_default()` never fails, so any 6-segment string
|
||||
/// would otherwise parse as `type=None`.
|
||||
#[test]
|
||||
fn from_str_rejects_unknown_partition() {
|
||||
assert!(ARN::from_str("arn:aws:replication::depl-123:bucket-a").is_err());
|
||||
assert!(ARN::from_str("not-an-arn").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14413,7 +14413,10 @@ mod tests {
|
||||
assert!(!target.secure);
|
||||
assert_eq!(target.target_bucket, "photos");
|
||||
assert_eq!(target.deployment_id, "remote");
|
||||
assert_eq!(target.arn, "arn:rustfs:replication::remote:photos");
|
||||
// Freshly minted ARNs use the `minio` partition so madmin-go tooling
|
||||
// can parse them; legacy `arn:rustfs:` targets are preserved as-is
|
||||
// (see the MinIO-era preservation test below).
|
||||
assert_eq!(target.arn, "arn:minio:replication::remote:photos");
|
||||
assert_eq!(target.region, "us-east-1");
|
||||
let credentials = target
|
||||
.credentials
|
||||
|
||||
Reference in New Issue
Block a user