mirror of
https://github.com/certbot/certbot.git
synced 2026-07-31 18:34:41 +02:00
Implement a consistent realpath function in certbot.compat.filesystem (#7242)
Fixes #7115 This PR creates a `realpath` method in `filesystem`, whose goal is to replace any call to `os.path.realpath` in Certbot. The reason is that `os.path.realpath` is broken on some versions of Python for Windows. See https://bugs.python.org/issue9949. The function created here works consistently across Linux and Windows. As for the other forbidden functions in `os` module, our `certbot.compat.os` will raise an exception if its `path.realpath` function is invoked, and using the `os` module from Python is forbidden from the pylint check implemented in our CI. Every call to `os.path.realpath` is corrected in `certbot` and `certbot-apache` modules. * Forbid os.path.realpath * Finish implementation * Use filesystem.realpath * Control symlink loops also for Linux * Add a test for forbidden method * Import a new object from os.path module * Use same approach of wrapping than certbot.compat.os * Correct errors * Fix dependencies * Make path module internal
This commit is contained in:
committed by
Brad Warren
parent
41a17f913e
commit
71ff47daad
@@ -48,18 +48,6 @@ class WindowsChmodTests(TempDirTestCase):
|
||||
self.assertFalse(filesystem._compare_dacls(ref_dacl_probe, cur_dacl_probe)) # pylint: disable=protected-access
|
||||
self.assertTrue(filesystem._compare_dacls(ref_dacl_link, cur_dacl_link)) # pylint: disable=protected-access
|
||||
|
||||
def test_symlink_loop_mitigation(self):
|
||||
link1_path = os.path.join(self.tempdir, 'link1')
|
||||
link2_path = os.path.join(self.tempdir, 'link2')
|
||||
link3_path = os.path.join(self.tempdir, 'link3')
|
||||
os.symlink(link1_path, link2_path)
|
||||
os.symlink(link2_path, link3_path)
|
||||
os.symlink(link3_path, link1_path)
|
||||
|
||||
with self.assertRaises(RuntimeError) as error:
|
||||
filesystem.chmod(link1_path, 0o755)
|
||||
self.assertTrue('link1 is a loop!' in str(error.exception))
|
||||
|
||||
def test_world_permission(self):
|
||||
everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)
|
||||
|
||||
@@ -320,7 +308,6 @@ class CopyOwnershipTest(test_util.TempDirTestCase):
|
||||
|
||||
class OsReplaceTest(test_util.TempDirTestCase):
|
||||
"""Test to ensure consistent behavior of rename method"""
|
||||
|
||||
def test_os_replace_to_existing_file(self):
|
||||
"""Ensure that replace will effectively rename src into dst for all platforms."""
|
||||
src = os.path.join(self.tempdir, 'src')
|
||||
@@ -335,6 +322,46 @@ class OsReplaceTest(test_util.TempDirTestCase):
|
||||
self.assertTrue(os.path.exists(dst))
|
||||
|
||||
|
||||
class RealpathTest(test_util.TempDirTestCase):
|
||||
"""Tests for realpath method"""
|
||||
def setUp(self):
|
||||
super(RealpathTest, self).setUp()
|
||||
self.probe_path = _create_probe(self.tempdir)
|
||||
|
||||
def test_symlink_resolution(self):
|
||||
# Absolute resolution
|
||||
link_path = os.path.join(self.tempdir, 'link_abs')
|
||||
os.symlink(self.probe_path, link_path)
|
||||
|
||||
self.assertEqual(self.probe_path, filesystem.realpath(self.probe_path))
|
||||
self.assertEqual(self.probe_path, filesystem.realpath(link_path))
|
||||
|
||||
# Relative resolution
|
||||
curdir = os.getcwd()
|
||||
link_path = os.path.join(self.tempdir, 'link_rel')
|
||||
probe_name = os.path.basename(self.probe_path)
|
||||
try:
|
||||
os.chdir(os.path.dirname(self.probe_path))
|
||||
os.symlink(probe_name, link_path)
|
||||
|
||||
self.assertEqual(self.probe_path, filesystem.realpath(probe_name))
|
||||
self.assertEqual(self.probe_path, filesystem.realpath(link_path))
|
||||
finally:
|
||||
os.chdir(curdir)
|
||||
|
||||
def test_symlink_loop_mitigation(self):
|
||||
link1_path = os.path.join(self.tempdir, 'link1')
|
||||
link2_path = os.path.join(self.tempdir, 'link2')
|
||||
link3_path = os.path.join(self.tempdir, 'link3')
|
||||
os.symlink(link1_path, link2_path)
|
||||
os.symlink(link2_path, link3_path)
|
||||
os.symlink(link3_path, link1_path)
|
||||
|
||||
with self.assertRaises(RuntimeError) as error:
|
||||
filesystem.realpath(link1_path)
|
||||
self.assertTrue('link1 is a loop!' in str(error.exception))
|
||||
|
||||
|
||||
def _get_security_dacl(target):
|
||||
return win32security.GetFileSecurity(target, win32security.DACL_SECURITY_INFORMATION)
|
||||
|
||||
|
||||
@@ -7,8 +7,12 @@ from certbot.compat import os
|
||||
class OsTest(unittest.TestCase):
|
||||
"""Unit tests for os module."""
|
||||
def test_forbidden_methods(self):
|
||||
# Checks for os module
|
||||
for method in ['chmod', 'chown', 'open', 'mkdir', 'makedirs', 'rename', 'replace']:
|
||||
self.assertRaises(RuntimeError, getattr(os, method))
|
||||
# Checks for os.path module
|
||||
for method in ['realpath']:
|
||||
self.assertRaises(RuntimeError, getattr(os.path, method))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user