22import errno
33import os
44import platform
5- from ctypes import c_uint32
5+ import threading
66from pathlib import Path
77
88import pytest
@@ -54,7 +54,7 @@ def landlock_supported() -> int:
5454 __NR_landlock_create_ruleset ,
5555 None ,
5656 ctypes .c_size_t (0 ),
57- c_uint32 (LANDLOCK_CREATE_RULESET_VERSION ),
57+ ctypes . c_uint32 (LANDLOCK_CREATE_RULESET_VERSION ),
5858 )
5959 if max_abi_version > 0 :
6060 return max_abi_version
@@ -72,31 +72,60 @@ def landlock_supported() -> int:
7272@pytest .mark .skipif (
7373 not landlock_supported (), reason = "Landlock support is not available on this system"
7474)
75- def test_read_sandboxing (request : pytest .FixtureRequest , sandbox_path : Path ):
76- restrict_access (
77- AccessFS .read ("/" ),
78- AccessFS .read (sandbox_path ),
79- # allow pytest caching, coverage, etc...
80- AccessFS .read_write (request .config .rootpath ),
81- )
82-
83- with pytest .raises (PermissionError ):
84- (sandbox_path / "some-dir" ).mkdir ()
85-
86- with pytest .raises (PermissionError ):
87- (sandbox_path / "some-file" ).touch ()
88-
89- with pytest .raises (PermissionError ):
90- (sandbox_path / "some-link" ).symlink_to ("file.txt" )
91-
92- for path in sandbox_path .rglob ("**/*" ):
93- if path .is_file () or path .is_symlink ():
94- with path .open ("rb" ) as f :
95- assert f .read () == FILE_CONTENT
96- with pytest .raises (PermissionError ):
97- assert path .open ("r+" )
98- with pytest .raises (PermissionError ):
99- assert path .unlink ()
100- elif path .is_dir ():
101- with pytest .raises (PermissionError ):
102- path .rmdir ()
75+ def test_read_sandboxing (request : pytest .FixtureRequest , sandbox_path : Path ): # noqa: C901
76+ exception = None
77+
78+ def _run_catching_exceptions (fn ):
79+ def wrapper ():
80+ __tracebackhide__ = True
81+ nonlocal exception
82+ try :
83+ fn ()
84+ except BaseException as exc :
85+ exception = exc
86+
87+ return wrapper
88+
89+ # Sandbox applies to the current thread and future threads spawned
90+ # from it.
91+ #
92+ # Running the test on a new thread keeps the main-thread
93+ # clean, so sandboxing won't interfere with other tests executed
94+ # after this one.
95+
96+ @_run_catching_exceptions
97+ def _run_in_thread ():
98+ restrict_access (
99+ AccessFS .read ("/" ),
100+ AccessFS .read (sandbox_path ),
101+ # allow pytest caching, coverage, etc...
102+ AccessFS .read_write (request .config .rootpath ),
103+ )
104+
105+ with pytest .raises (PermissionError ):
106+ (sandbox_path / "some-dir" ).mkdir ()
107+
108+ with pytest .raises (PermissionError ):
109+ (sandbox_path / "some-file" ).touch ()
110+
111+ with pytest .raises (PermissionError ):
112+ (sandbox_path / "some-link" ).symlink_to ("file.txt" )
113+
114+ for path in sandbox_path .rglob ("**/*" ):
115+ if path .is_file () or path .is_symlink ():
116+ with path .open ("rb" ) as f :
117+ assert f .read () == FILE_CONTENT
118+ with pytest .raises (PermissionError ):
119+ assert path .open ("r+" )
120+ with pytest .raises (PermissionError ):
121+ assert path .unlink ()
122+ elif path .is_dir ():
123+ with pytest .raises (PermissionError ):
124+ path .rmdir ()
125+
126+ t = threading .Thread (target = _run_in_thread )
127+ t .start ()
128+ t .join ()
129+ __tracebackhide__ = True
130+ if exception :
131+ raise exception
0 commit comments