using ClawdDotNet.Core.Storage; using ClawdDotNet.Core.Tests.Infrastructure; using Shouldly; namespace ClawdDotNet.Core.Tests.Storage; /// /// #575: Auf der Test-VM (umask 0002) ging InstanceSettings.json beim ersten Speichern von /// 0600 auf 0664, Protokolle entstanden mit 0664. Unter Windows nicht aussagekraeftig. /// 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 { /* Aufraeumen ist best effort */ } } private const UnixFileMode NurBesitzer = UnixFileMode.UserRead | UnixFileMode.UserWrite; [LinuxFact] [System.Runtime.Versioning.SupportedOSPlatform("linux")] public void AtomicFile_ersetzt_eine_offene_Datei_durch_eine_nur_fuer_den_Besitzer() { var pfad = Path.Combine(_dir, "InstanceSettings.json"); File.WriteAllText(pfad, "{}"); File.SetUnixFileMode(pfad, NurBesitzer | UnixFileMode.GroupRead | UnixFileMode.OtherRead); AtomicFile.WriteAllText(pfad, "{\"a\":1}"); File.GetUnixFileMode(pfad).ShouldBe(NurBesitzer); } [LinuxFact] [System.Runtime.Versioning.SupportedOSPlatform("linux")] public void AtomicFile_legt_neue_Dateien_nur_fuer_den_Besitzer_an() { var pfad = Path.Combine(_dir, "neu.json"); AtomicFile.WriteAllText(pfad, "{}"); File.GetUnixFileMode(pfad).ShouldBe(NurBesitzer); } [LinuxFact] [System.Runtime.Versioning.SupportedOSPlatform("linux")] public void OpenAppend_legt_neue_Dateien_nur_fuer_den_Besitzer_an() { var pfad = Path.Combine(_dir, "protokoll.log"); using (var stream = OwnerOnlyFile.OpenAppend(pfad)) stream.WriteByte((byte)'x'); File.GetUnixFileMode(pfad).ShouldBe(NurBesitzer); } [Fact] public void OpenAppend_haengt_an_statt_zu_ueberschreiben() { var pfad = Path.Combine(_dir, "anhang.txt"); foreach (var teil in new[] { "eins", "zwei" }) { using var stream = OwnerOnlyFile.OpenAppend(pfad); using var writer = new StreamWriter(stream); writer.Write(teil); } File.ReadAllText(pfad).ShouldBe("einszwei"); } }