using ClawdDotNet.Core.Storage; using ClawdDotNet.Core.Tests.Infrastructure; using Shouldly; namespace ClawdDotNet.Core.Tests.Storage; /// /// #575: On the test VM (umask 0002) InstanceSettings.json went from /// 0600 to 0664 on the first save, logs were created with 0664. Not meaningful under Windows. /// public sealed class OwnerOnlyFileTests : IDisposable { private readonly string _dir = Path.Combine(Path.GetTempPath(), "clawd-owner-" + Guid.NewGuid().ToString("N")[..8]); public OwnerOnlyFileTests() => Directory.CreateDirectory(_dir); public void Dispose() { try { Directory.Delete(_dir, recursive: true); } catch { /* Cleaning up is best effort */ } } private const UnixFileMode OwnerOnly = UnixFileMode.UserRead | UnixFileMode.UserWrite; [LinuxFact] [System.Runtime.Versioning.SupportedOSPlatform("linux")] public void AtomicFile_replaces_an_open_file_with_an_owner_only_one() { var path = Path.Combine(_dir, "InstanceSettings.json"); File.WriteAllText(path, "{}"); File.SetUnixFileMode(path, OwnerOnly | UnixFileMode.GroupRead | UnixFileMode.OtherRead); AtomicFile.WriteAllText(path, "{\"a\":1}"); File.GetUnixFileMode(path).ShouldBe(OwnerOnly); } [LinuxFact] [System.Runtime.Versioning.SupportedOSPlatform("linux")] public void AtomicFile_creates_new_files_owner_only() { var path = Path.Combine(_dir, "neu.json"); AtomicFile.WriteAllText(path, "{}"); File.GetUnixFileMode(path).ShouldBe(OwnerOnly); } [LinuxFact] [System.Runtime.Versioning.SupportedOSPlatform("linux")] public void OpenAppend_creates_new_files_owner_only() { var path = Path.Combine(_dir, "protokoll.log"); using (var stream = OwnerOnlyFile.OpenAppend(path)) stream.WriteByte((byte)'x'); File.GetUnixFileMode(path).ShouldBe(OwnerOnly); } [Fact] public void OpenAppend_appends_instead_of_overwriting() { var path = Path.Combine(_dir, "anhang.txt"); foreach (var part in new[] { "eins", "zwei" }) { using var stream = OwnerOnlyFile.OpenAppend(path); using var writer = new StreamWriter(stream); writer.Write(part); } File.ReadAllText(path).ShouldBe("einszwei"); } }