fix(config): preserve permissions during atomic save

This commit is contained in:
Xubin Ren
2026-07-21 17:33:39 +08:00
parent 28102382af
commit b2cf37da4a
2 changed files with 19 additions and 0 deletions
+6
View File
@@ -5,6 +5,7 @@ import json
import os
import re
import shutil
import stat
import time
import uuid
from contextlib import suppress
@@ -454,8 +455,13 @@ def _cleanup_tool_result_buckets(root: Path, current_bucket: Path) -> None:
def _write_text_atomic(path: Path, content: str) -> None:
tmp = path.with_name(f".{path.name}.{uuid.uuid4().hex}.tmp")
existing_mode: int | None = None
with suppress(OSError):
existing_mode = stat.S_IMODE(path.stat().st_mode)
try:
with open(tmp, "w", encoding="utf-8") as f:
if existing_mode is not None:
os.chmod(tmp, existing_mode)
f.write(content)
f.flush()
os.fsync(f.fileno())
+13
View File
@@ -3,6 +3,8 @@
from __future__ import annotations
import json
import os
import stat
from pathlib import Path
import pytest
@@ -18,6 +20,17 @@ def test_save_config_round_trips(tmp_path: Path) -> None:
assert loaded.agents.defaults.model
@pytest.mark.skipif(os.name == "nt", reason="Windows does not expose POSIX file modes")
def test_save_config_preserves_existing_file_mode(tmp_path: Path) -> None:
path = tmp_path / "config.json"
path.write_text("{}", encoding="utf-8")
path.chmod(0o600)
save_config(Config(), path)
assert stat.S_IMODE(path.stat().st_mode) == 0o600
def test_save_config_preserves_existing_file_when_write_fails(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None: