Files
ClawdDotNet/tests/ClawdDotNet.App.Tests/Services/InstanceSecretRoundtripTests.cs
T
RichardandClaude Opus 5.5 837a634a22 Stufe 4c (#764): Kommentare in C#, WebUI-Skripten, CSS und HTML auf Englisch
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>
2026-10-04 12:45:03 +02:00

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");
}
}