@@ -141,6 +141,87 @@ async fn test_aws_expired_credentials() {
141141 validates_aws_files ( & temp_dir, & credentials, & datastores_info) ;
142142}
143143
144+ /// Test that stale Satori profiles are removed when user loses access to datastores
145+ /// User had S3 and Athena, now only has Athena. S3 profile should be removed.
146+ #[ tokio:: test]
147+ async fn test_aws_stale_profiles_removed ( ) {
148+ let temp_dir = temp_dir:: generate ( ) ;
149+ let credentials = get_old_credentials_expire_two_hours ( ) ;
150+ let datastores_info = get_mock_datastores ( "athena_only_datastores.json" ) ;
151+ let datastores_entries_response_path = get_access_details_db_empty_response_path ( ) ;
152+
153+ // Start with files that have both S3 and Athena profiles
154+ let old_config = read_ini_file ( AWS_CREDENTIALS_DIR , "stale_config_with_s3" ) ;
155+ let old_credentials = read_ini_file ( AWS_CREDENTIALS_DIR , "stale_credentials_with_s3" ) ;
156+
157+ write_credentials_temp_dir ( & credentials, & temp_dir) ;
158+ write_datastores_temp_dir ( & datastores_info, & temp_dir) ;
159+ write_aws_temp_dir ( & temp_dir, old_config, old_credentials) ;
160+
161+ run_aws_with_server_assert_no_calls_to_server (
162+ & temp_dir,
163+ & datastores_entries_response_path,
164+ AwsBuilder :: default ( ) ,
165+ )
166+ . await ;
167+
168+ // Read the resulting files
169+ let actual_credentials = read_actual_aws_file ( & temp_dir, "credentials" ) ;
170+ let actual_config = read_actual_aws_file ( & temp_dir, "config" ) ;
171+
172+ // Verify S3 profile was removed from credentials
173+ assert ! (
174+ actual_credentials. section( Some ( S3_PROFILE ) ) . is_none( ) ,
175+ "S3 profile should be removed from credentials"
176+ ) ;
177+
178+ // Verify S3 profile was removed from config
179+ let s3_config_section = format ! ( "profile {}" , S3_PROFILE ) ;
180+ assert ! (
181+ actual_config. section( Some ( & s3_config_section) ) . is_none( ) ,
182+ "S3 profile should be removed from config"
183+ ) ;
184+
185+ // Verify Athena profile still exists in credentials
186+ assert ! (
187+ actual_credentials. section( Some ( ATHENA_PROFILE ) ) . is_some( ) ,
188+ "Athena profile should still exist in credentials"
189+ ) ;
190+
191+ // Verify Athena profile still exists in config
192+ let athena_config_section = format ! ( "profile {}" , ATHENA_PROFILE ) ;
193+ assert ! (
194+ actual_config
195+ . section( Some ( & athena_config_section) )
196+ . is_some( ) ,
197+ "Athena profile should still exist in config"
198+ ) ;
199+
200+ // Verify non-Satori profiles are preserved in credentials
201+ assert ! (
202+ actual_credentials. section( Some ( "default" ) ) . is_some( ) ,
203+ "Default profile should be preserved"
204+ ) ;
205+ assert ! (
206+ actual_credentials
207+ . section( Some ( "personal-account" ) )
208+ . is_some( ) ,
209+ "Personal account profile should be preserved"
210+ ) ;
211+
212+ // Verify non-Satori profiles are preserved in config
213+ assert ! (
214+ actual_config. section( Some ( "default" ) ) . is_some( ) ,
215+ "Default config should be preserved"
216+ ) ;
217+ assert ! (
218+ actual_config
219+ . section( Some ( "profile personal-account" ) )
220+ . is_some( ) ,
221+ "Personal account config should be preserved"
222+ ) ;
223+ }
224+
144225async fn run_aws_with_server_assert_no_calls_to_server (
145226 temp_dir : & TempDir ,
146227 datastores_info_file_path : & Path ,
0 commit comments