using ClawdDotNet.App.Services; using ClawdDotNet.Core.Config; using Shouldly; namespace ClawdDotNet.App.Tests.Services; /// /// The instance's credentials must survive the way to disk and back. /// /// SaveInstanceConfig encrypted when writing, but LoadInstanceConfig /// did not decrypt when reading. Whatever had once been saved via the user interface /// came back as enc:v2:… and was used as the value — the OpenRouter key /// thus went to the API encrypted. /// /// It went undiscovered because ConfigLoader.LoadAsync does it right /// and is not called at all in the running program: only Migrate /// of that class is needed. /// public sealed class InstanceSecretRoundtripTests { [Fact] public void Zugangsdaten_kommen_im_Klartext_zurueck() { using var host = new TestHost(); host.Host.Instance.OpenRouterApiKey = "sk-or-v1-beispielschluessel"; host.Host.Instance.WebUiToken = "ein-hinreichend-langes-token"; host.Host.Instance.Watchdog.AgentToken = "dc-token-beispiel"; host.Host.SaveInstance(new InstanceChange(InstanceChangeKind.Settings)); var geladen = host.Host.Directories.LoadInstanceConfig(host.Host.InstancePath); geladen.OpenRouterApiKey.ShouldBe("sk-or-v1-beispielschluessel"); geladen.WebUiToken.ShouldBe("ein-hinreichend-langes-token"); geladen.Watchdog.AgentToken.ShouldBe("dc-token-beispiel"); } [Fact] public void In_der_Datei_stehen_sie_trotzdem_geschuetzt() { // The counter-check: decrypting when loading must not mean that nothing is // encrypted any more. using var host = new TestHost(); host.Host.Instance.OpenRouterApiKey = "sk-or-v1-beispielschluessel"; host.Host.SaveInstance(new InstanceChange(InstanceChangeKind.Settings)); var rohtext = File.ReadAllText( Path.Combine(host.Host.InstancePath, "InstanceSettings.json")); rohtext.ShouldNotContain("sk-or-v1-beispielschluessel"); } [Fact] public void Klartext_aus_aelteren_Dateien_bleibt_lesbar() { // Decrypting must be safely applicable to something that was never encrypted // — otherwise the first start after the update would break every existing instance. using var host = new TestHost(); var pfad = Path.Combine(host.Host.InstancePath, "InstanceSettings.json"); File.WriteAllText(pfad, """ { "instanceId": "alt", "instanceName": "Alt", "openRouterApiKey": "klartext-von-hand-eingetragen", "webUiToken": "auch-klartext" } """); var geladen = host.Host.Directories.LoadInstanceConfig(host.Host.InstancePath); geladen.OpenRouterApiKey.ShouldBe("klartext-von-hand-eingetragen"); geladen.WebUiToken.ShouldBe("auch-klartext"); } [Fact] public void Zweimal_speichern_verschluesselt_nicht_zweimal() { using var host = new TestHost(); host.Host.Instance.WebUiToken = "ein-hinreichend-langes-token"; host.Host.SaveInstance(new InstanceChange(InstanceChangeKind.Settings)); host.Host.SaveInstance(new InstanceChange(InstanceChangeKind.Settings)); host.Host.Directories.LoadInstanceConfig(host.Host.InstancePath) .WebUiToken.ShouldBe("ein-hinreichend-langes-token"); } }