@@ -425,6 +425,37 @@ def test_login_dry_run(self):
425425 self .subprocess_utils .check_output .assert_not_called ()
426426 self .assertFalse (os .path .exists (self .test_netrc_path ))
427427
428+ @mock .patch ('awscli.customizations.codeartifact.login.is_macos' , False )
429+ def test_login_adjusts_permissions_on_preexisting_file (self ):
430+ existing_content = (
431+ f'machine { self .hostname } login token password old-token\n '
432+ )
433+ with open (self .test_netrc_path , 'w' ) as f :
434+ f .write (existing_content )
435+ os .chmod (self .test_netrc_path , 0o644 )
436+ self .test_subject .login ()
437+ file_mode = os .stat (self .test_netrc_path ).st_mode
438+ self .assertEqual (stat .S_IMODE (file_mode ), 0o600 )
439+
440+ @mock .patch ('awscli.customizations.codeartifact.login.is_macos' , False )
441+ @mock .patch ('sys.stderr' )
442+ @mock .patch ('os.chmod' , side_effect = OSError (
443+ errno .EPERM , 'Operation not permitted'
444+ ))
445+ def test_login_writes_error_when_chmod_fails (
446+ self , mock_chmod , mock_stderr
447+ ):
448+ existing_content = (
449+ f'machine { self .hostname } login token password old-token\n '
450+ )
451+ with open (self .test_netrc_path , 'w' ) as f :
452+ f .write (existing_content )
453+ self .test_subject .login ()
454+ mock_stderr .write .assert_any_call (
455+ 'Unable to set file permissions for %s: '
456+ '[Errno 1] Operation not permitted%s'
457+ % (self .test_netrc_path , os .linesep )
458+ )
428459
429460class TestNuGetLogin (unittest .TestCase ):
430461 _NUGET_INDEX_URL_FMT = NuGetLogin ._NUGET_INDEX_URL_FMT
@@ -1316,6 +1347,43 @@ def test_login_existing_pypi_rc_with_codeartifact_not_clobbered(self):
13161347 password = 'JgCXIr5xGG' ,
13171348 )
13181349
1350+ def test_login_sets_secure_permissions_on_new_file (self ):
1351+ self .assertFalse (os .path .exists (self .test_pypi_rc_path ))
1352+ self .test_subject .login ()
1353+ file_mode = os .stat (self .test_pypi_rc_path ).st_mode
1354+ self .assertEqual (stat .S_IMODE (file_mode ), 0o600 )
1355+
1356+ def test_login_adjusts_permissions_on_preexisting_file (self ):
1357+ existing_pypi_rc = '''\
1358+ [distutils]
1359+ index-servers=
1360+ pypi
1361+
1362+ [pypi]
1363+ repository: http://www.python.org/pypi/
1364+ username: test
1365+ password: JgCXIr5xGG
1366+ '''
1367+ with open (self .test_pypi_rc_path , 'w' ) as f :
1368+ f .write (existing_pypi_rc )
1369+ os .chmod (self .test_pypi_rc_path , 0o644 )
1370+ self .test_subject .login ()
1371+ file_mode = os .stat (self .test_pypi_rc_path ).st_mode
1372+ self .assertEqual (stat .S_IMODE (file_mode ), 0o600 )
1373+
1374+ @mock .patch ('sys.stderr' )
1375+ @mock .patch ('os.chmod' , side_effect = OSError (
1376+ errno .EPERM , 'Operation not permitted'
1377+ ))
1378+
1379+ def test_login_writes_error_when_chmod_fails (self , mock_chmod , mock_stderr ):
1380+ self .test_subject .login ()
1381+ mock_stderr .write .assert_any_call (
1382+ 'Unable to set file permissions for %s: '
1383+ '[Errno 1] Operation not permitted%s'
1384+ % (self .test_pypi_rc_path , os .linesep )
1385+ )
1386+
13191387 def test_login_existing_invalid_pypi_rc_error (self ):
13201388 # This is an invalid pypirc as the list of servers are expected under
13211389 # an 'index-servers' option instead of 'servers'.
0 commit comments