@@ -42,6 +42,18 @@ pub struct CloudFront {
4242 static_distribution_id : String ,
4343}
4444
45+ /// Normalizes CloudFront invalidation entries.
46+ ///
47+ /// Path invalidations must start with `/`. Cache-tag invalidations already start with `#`
48+ /// and must remain unchanged so CloudFront recognizes them as cache tags.
49+ fn normalize_invalidation_paths ( paths : & mut [ String ] ) {
50+ for path in paths {
51+ if !path. starts_with ( '/' ) && !path. starts_with ( '#' ) {
52+ * path = format ! ( "/{path}" ) ;
53+ }
54+ }
55+ }
56+
4557impl CloudFront {
4658 pub fn from_environment ( ) -> Option < Self > {
4759 let access_key = match dotenvy:: var ( "AWS_ACCESS_KEY" ) {
@@ -111,12 +123,7 @@ impl CloudFront {
111123 let distribution_id = self . distribution_id ( distribution) ;
112124 let now = chrono:: offset:: Utc :: now ( ) . timestamp_micros ( ) ;
113125
114- // We need to ensure that paths have a starting slash.
115- for path in paths. iter_mut ( ) {
116- if !path. starts_with ( '/' ) {
117- * path = format ! ( "/{path}" ) ;
118- }
119- }
126+ normalize_invalidation_paths ( & mut paths) ;
120127
121128 let paths = Paths :: builder ( )
122129 // It looks like you have to set quantity even if you provide a full blown Vec, because
@@ -146,3 +153,24 @@ impl CloudFront {
146153 . inspect_err ( |error| warn ! ( "Invalidation request failed: {error}" ) ) ?)
147154 }
148155}
156+
157+ #[ cfg( test) ]
158+ mod tests {
159+ use super :: * ;
160+
161+ #[ test]
162+ fn normalizes_invalidation_paths ( ) {
163+ let mut paths = vec ! [
164+ "index/config.json" . into( ) ,
165+ "/db-dump.tar.gz" . into( ) ,
166+ "#crate:serde" . into( ) ,
167+ ] ;
168+
169+ normalize_invalidation_paths ( & mut paths) ;
170+
171+ assert_eq ! (
172+ paths,
173+ [ "/index/config.json" , "/db-dump.tar.gz" , "#crate:serde" ]
174+ ) ;
175+ }
176+ }
0 commit comments