Skip to content

Commit 8eb7827

Browse files
committed
fix(craft): count scan and stat failures so partial manifests admit it
A directory listing that fails after its open, or a child that vanishes between scandir and stat, previously dropped content silently. Both now increment skipped_unreadable so a partial manifest is distinguishable from a complete one.
1 parent 31100d3 commit 8eb7827

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

backend/onyx/server/features/build/sandbox/image/sandbox_daemon/manifest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ def _walk_directory(walk: _Walk, dir_fd: int, prefix: str, depth: int) -> None:
115115
resp.truncated = True
116116
children = children[:MANIFEST_MAX_DIR_CHILDREN]
117117
except OSError:
118+
# The listing failed after the open, so the directory's contents
119+
# are unknown: admit the gap instead of looking complete.
120+
resp.skipped_unreadable += 1
118121
return
119122
for child in children:
120123
if len(resp.entries) >= MANIFEST_MAX_ENTRIES:
@@ -126,6 +129,8 @@ def _walk_directory(walk: _Walk, dir_fd: int, prefix: str, depth: int) -> None:
126129
try:
127130
st = child.stat(follow_symlinks=False)
128131
except OSError:
132+
# Vanished or unreadable between scandir and stat.
133+
resp.skipped_unreadable += 1
129134
continue
130135
relative = f"{prefix}{child.name}"
131136
if stat.S_ISLNK(st.st_mode):

backend/tests/unit/onyx/server/features/craft/sandbox/test_outputs_manifest.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,23 @@ def test_special_files_skipped(manifest_module: ModuleType, tmp_path: Path) -> N
131131
assert result.skipped_special == 1
132132

133133

134+
def test_unreadable_directory_counted_not_listed(
135+
manifest_module: ModuleType, tmp_path: Path
136+
) -> None:
137+
if os.geteuid() == 0:
138+
pytest.skip("root bypasses directory permissions")
139+
locked = tmp_path / "locked"
140+
locked.mkdir()
141+
(locked / "hidden.txt").write_bytes(b"x")
142+
locked.chmod(0o000)
143+
try:
144+
result = manifest_module.build_manifest_for_root(tmp_path)
145+
finally:
146+
locked.chmod(0o755)
147+
assert [e.path for e in result.entries] == []
148+
assert result.skipped_unreadable == 1
149+
150+
134151
def test_truncation_flags_instead_of_growing(
135152
manifest_module: ModuleType,
136153
tmp_path: Path,

0 commit comments

Comments
 (0)