fix: keep the mirror readable under a umask that masks the owner's read bit
Build and publish container / build (pull_request) Successful in 15m16s
Build and publish container / build (pull_request) Successful in 15m16s
The umask handling added for group access cleared only the group bits and left owner and other to the environment. A container whose umask carries 0400 then produces mirror directories of mode 0300: writable and enterable, unreadable to the very run that created them, and unreadable to anything serving the share. Clear the owner read and execute bits from the umask as well. The `other` bits stay where the environment puts them, because whether the mirror is world-readable is a real policy question; being able to read a directory the process itself just created is not. Files were never exposed to this: mkstemp sets 0600 outright and copy2 takes the source file's mode, both ignoring the umask.
This commit is contained in:
@@ -27,6 +27,21 @@ def tight_umask():
|
||||
os.umask(previous)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def owner_hostile_umask():
|
||||
"""Return a callable applying a umask that masks off the owner's read bit.
|
||||
|
||||
Unusual, but it is what produces a mirror tree of mode 0300 -- writable and
|
||||
enterable, unreadable to the very process that built it. Applied on demand
|
||||
rather than for the whole test, because the source library is built by
|
||||
something else entirely and the same umask would make the test's own
|
||||
fixtures unreadable before the run under test even started.
|
||||
"""
|
||||
previous = os.umask(0o022)
|
||||
yield lambda: os.umask(0o477)
|
||||
os.umask(previous)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def make_flac():
|
||||
"""Return a factory writing a short tagged FLAC file."""
|
||||
|
||||
@@ -222,6 +222,27 @@ def test_mirror_directories_are_group_traversable(tmp_path, make_flac, tight_uma
|
||||
assert mode & stat.S_IXGRP, directory
|
||||
|
||||
|
||||
def test_mirror_directories_survive_an_owner_hostile_umask(
|
||||
tmp_path, make_flac, owner_hostile_umask
|
||||
):
|
||||
"""A umask carrying 0400 otherwise builds a tree the run cannot read back."""
|
||||
source = tmp_path / "src"
|
||||
mirror = tmp_path / "dst"
|
||||
make_flac(source / "Artist" / "Album" / "a.flac")
|
||||
|
||||
# Applied only now: the library already exists, and the umask under test is
|
||||
# the one the container starts this run with.
|
||||
owner_hostile_umask()
|
||||
run(source, mirror)
|
||||
|
||||
for directory in (mirror, mirror / "Artist", mirror / "Artist" / "Album"):
|
||||
mode = directory.stat().st_mode
|
||||
assert mode & stat.S_IRUSR, directory
|
||||
assert mode & stat.S_IXUSR, directory
|
||||
assert mode & stat.S_IRGRP, directory
|
||||
assert mode & stat.S_IXGRP, directory
|
||||
|
||||
|
||||
def test_private_mirror_file_is_repaired_without_re_encoding(tmp_path, make_flac):
|
||||
"""A mirror written by an older version has a correct mtime, so nothing
|
||||
else in the pass would revisit it."""
|
||||
|
||||
Reference in New Issue
Block a user