From c7ce0db4fa83c5981d4d74e6c906465ccf3d2279 Mon Sep 17 00:00:00 2001 From: ai-ag2026 <261867348+ai-ag2026@users.noreply.github.com> Date: Fri, 10 Jul 2026 06:26:30 +0200 Subject: [PATCH] Handle unsupported ownership transfer in atomic writes --- api/paths.py | 13 ++++++++++++- tests/test_5774b_atomic_config_writes.py | 11 +++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/api/paths.py b/api/paths.py index 2fad3194..7254db26 100644 --- a/api/paths.py +++ b/api/paths.py @@ -144,7 +144,18 @@ def _atomic_write_text(path: Path, text: str, *, encoding: str = "utf-8") -> Non if existing_stat is not None and hasattr(os, "fchown"): try: os.fchown(fd, existing_stat.st_uid, existing_stat.st_gid) - except (PermissionError, NotImplementedError): + except (OSError, NotImplementedError) as exc: + unsupported_ownership_errnos = { + errno.EINVAL, + errno.ENOSYS, + errno.ENOTSUP, + } + if ( + isinstance(exc, OSError) + and not isinstance(exc, PermissionError) + and exc.errno not in unsupported_ownership_errnos + ): + raise os.close(fd) owns_fd = False os.unlink(tmp) diff --git a/tests/test_5774b_atomic_config_writes.py b/tests/test_5774b_atomic_config_writes.py index a4200a3a..bb0f06d5 100644 --- a/tests/test_5774b_atomic_config_writes.py +++ b/tests/test_5774b_atomic_config_writes.py @@ -99,15 +99,22 @@ def test_atomic_write_preserves_existing_group(tmp_path: Path) -> None: @pytest.mark.skipif(not hasattr(os, "fchown"), reason="POSIX ownership semantics") +@pytest.mark.parametrize( + "failure", + [ + PermissionError("simulated ownership denial"), + OSError(errno.EINVAL, "simulated unsupported ownership transfer"), + ], +) def test_fchown_denial_falls_back_without_temp_debris( - tmp_path: Path, monkeypatch + tmp_path: Path, monkeypatch, failure: OSError ) -> None: """A writer unable to transfer ownership must keep the old inode contract.""" target = tmp_path / "config.yaml" target.write_text("old: true\n", encoding="utf-8") def _deny_fchown(*_args) -> None: - raise PermissionError("simulated ownership denial") + raise failure monkeypatch.setattr(os, "fchown", _deny_fchown)