Rund 2.600 Kommentarblöcke in 310 C#-Dateien übersetzt, Begründungen vollständig erhalten: blockweise gleiche Anzahl wie vorher, kein Block unter 60 % seiner Länge, der Code außerhalb der Kommentare per Tokenizer byte-identisch geprüft. Zitate deutscher Oberflächentexte und Testdaten bleiben deutsch. WebUI: Kommentare in JS/CSS/HTML übersetzt, JSDoc-@param an die in 4b umbenannten Parameter angeglichen. Dabei behoben: - 4b hatte "tag" (HTML-Tag) als deutsches "Tag" gelesen und zu "dayValue" gemacht (makeElement, svg, Tagesübersicht) - zurück auf tag/day. - Aufgaben "InProgress" bekamen die Plakettenart "laufend", für die es nie eine CSS-Klasse gab - jetzt "success" wie laufende Instanzen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
93 lines
3.4 KiB
C#
93 lines
3.4 KiB
C#
using ClawdDotNet.App.Services;
|
|
using ClawdDotNet.Core.Config;
|
|
using Shouldly;
|
|
|
|
namespace ClawdDotNet.App.Tests.Services;
|
|
|
|
/// <summary>
|
|
/// The instance's credentials must survive the way to disk and back.
|
|
///
|
|
/// <para><c>SaveInstanceConfig</c> encrypted when writing, but <c>LoadInstanceConfig</c>
|
|
/// did not decrypt when reading. Whatever had once been saved via the user interface
|
|
/// came back as <c>enc:v2:…</c> and was used as the value — the OpenRouter key
|
|
/// thus went to the API encrypted.</para>
|
|
///
|
|
/// <para>It went undiscovered because <c>ConfigLoader.LoadAsync</c> does it right
|
|
/// and is not called at all in the running program: only <c>Migrate</c>
|
|
/// of that class is needed.</para>
|
|
/// </summary>
|
|
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");
|
|
}
|
|
}
|