@@ -45,23 +45,14 @@ public void testSnapshotNameValidation()
4545
4646 try (WithProperties p = new WithProperties ().set (CassandraRelevantProperties .SNAPSHOT_NAME_VALIDATION , true ))
4747 {
48- // Previously-allowed alphanumerics, '-' and '_' must still be accepted.
48+ // Only alphanumerics, '-', '_' and '.' are accepted.
4949 validate ("atag" , USER );
5050 validate ("a-tag" , USER );
5151 validate ("a_tag" , USER );
5252 validate ("a_tag" + Instant .now ().toEpochMilli (), USER );
5353 validate ("a_tag_1and_something2-more" , USER );
5454 validate ("a" .repeat (255 ), USER );
55-
56- // AWS S3 "Safe characters" newly accepted by the relaxed allowlist:
57- // ! . * ' ( )
58- // See https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-guidelines
5955 validate ("snap.2026-05-20" , USER );
60- validate ("important!" , USER );
61- validate ("backup*" , USER );
62- validate ("o'snap" , USER );
63- validate ("snap(1)" , USER );
64- validate ("!._-*'()" , USER );
6556 // Dots embedded in a name are not traversal: with '/' excluded, "a..tag" is just a literal directory.
6657 validate ("a..tag" , USER );
6758
@@ -75,12 +66,26 @@ public void testSnapshotNameValidation()
7566 .isInstanceOf (IllegalArgumentException .class )
7667 .hasMessageContaining ("Snapshot name must not be more than 255 characters long" );
7768
78- // '/' is not in the S3-safe set; this is what kills traversal attempts like "../../mysnapshot".
69+ // '/' is not in the allowed set; this is what kills traversal attempts like "../../mysnapshot".
7970 assertThatThrownBy (() -> validate ('a' + sep + "tag" , USER ))
8071 .isInstanceOf (IllegalArgumentException .class )
8172 .hasMessage ("Snapshot name cannot contain " + sep );
8273
83- // Other characters outside the S3-safe set must still be rejected.
74+ // The shell-significant S3 "safe" characters (! * ' ( )) are deliberately NOT allowed.
75+ assertThatThrownBy (() -> validate ("important!" , USER ))
76+ .isInstanceOf (IllegalArgumentException .class )
77+ .hasMessage ("Snapshot name contains illegal characters: important!" );
78+ assertThatThrownBy (() -> validate ("backup*" , USER ))
79+ .isInstanceOf (IllegalArgumentException .class )
80+ .hasMessage ("Snapshot name contains illegal characters: backup*" );
81+ assertThatThrownBy (() -> validate ("o'snap" , USER ))
82+ .isInstanceOf (IllegalArgumentException .class )
83+ .hasMessage ("Snapshot name contains illegal characters: o'snap" );
84+ assertThatThrownBy (() -> validate ("snap(1)" , USER ))
85+ .isInstanceOf (IllegalArgumentException .class )
86+ .hasMessage ("Snapshot name contains illegal characters: snap(1)" );
87+
88+ // Other characters outside the allowed set must still be rejected.
8489 assertThatThrownBy (() -> validate ("a tag" , USER ))
8590 .isInstanceOf (IllegalArgumentException .class )
8691 .hasMessage ("Snapshot name contains illegal characters: a tag" );
@@ -101,9 +106,12 @@ public void testSnapshotNameValidation()
101106
102107 try (WithProperties p = new WithProperties ().set (CassandraRelevantProperties .SNAPSHOT_NAME_VALIDATION , false ))
103108 {
104- // Previously-rejected characters are now accepted: space, ':', and other non-S3-safe chars.
109+ // The character check is bypassed entirely: space, ':', and the now-disallowed
110+ // shell-significant characters (! * ' ( )) are all accepted.
105111 assertThatCode (() -> validate ("a tag" , USER )).doesNotThrowAnyException ();
106112 assertThatCode (() -> validate ("a:tag" , USER )).doesNotThrowAnyException ();
113+ assertThatCode (() -> validate ("important!" , USER )).doesNotThrowAnyException ();
114+ assertThatCode (() -> validate ("snap(1)" , USER )).doesNotThrowAnyException ();
107115
108116 assertThatCode (() -> validate ("a" .repeat (256 ), USER )).doesNotThrowAnyException ();
109117 assertThatCode (() -> validate ("a" .repeat (250 ), SnapshotType .UPGRADE )).doesNotThrowAnyException ();
0 commit comments