Commit graph

6 commits

Author SHA1 Message Date
ai-ag2026
83bd7125bd fix: avoid racy umask probe for config writes 2026-07-18 13:47:04 +02:00
ai-ag2026
2706433802 fix: preserve config extended attributes 2026-07-18 13:47:04 +02:00
ai-ag2026
297535bfba Preserve hard-linked configs during atomic writes 2026-07-18 13:47:04 +02:00
ai-ag2026
c7ce0db4fa Handle unsupported ownership transfer in atomic writes 2026-07-18 13:47:04 +02:00
ai-ag2026
828b244031 Atomic config.yaml writes to survive mid-write crashes
config.yaml and profile config.yaml were persisted with a plain
Path.write_text(), which truncates the target before writing.  A crash
(or exception) after the truncate but before the full payload was
flushed left the live config truncated/corrupt, so the next agent/WebUI
start failed to parse it (availability regression).

Extract a shared api.paths._atomic_write_text() helper (tempfile in the
same dir -> write -> flush + os.fsync -> os.replace; unlink tmp on
error), mirroring the existing .env / cost-snapshot atomic pattern in
api.providers, and apply it to _save_yaml_config_file (api.config) and
the two profile model-config writers (api.profiles).  On any mid-write
failure os.replace never runs, so the original file stays byte-for-byte
intact.

Preserve the target's permissions: tempfile.mkstemp() hard-codes 0600
and os.replace carries the temp file's mode onto the target, so without
an explicit chmod every save would silently tighten a group/other-
readable config.yaml (the homelab install ships 0644, profiles 0664)
down to owner-only.  Copy the existing file's mode before the replace,
falling back to the umask-adjusted 0666 for a new file.  config.yaml
holds no secrets, so that tightening would be a regression, not
hardening (unlike .env, which stays 0600 in api.providers).

settings.json is intentionally left untouched here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 13:47:04 +02:00
AJV20
d8471a7d87 fix(profiles): avoid config import cycle 2026-06-01 05:05:16 +00:00