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>
123 lines
3.9 KiB
C#
123 lines
3.9 KiB
C#
using ClawdDotNet.Core.Config;
|
|
using Shouldly;
|
|
|
|
namespace ClawdDotNet.Web.Tests;
|
|
|
|
/// <summary>
|
|
/// The web UI turns a local application into a network service that controls agents
|
|
/// with file, mail, FTP and database access. What is checked here are
|
|
/// not subtleties of configuration, but the conditions under which it
|
|
/// may come up at all.
|
|
/// </summary>
|
|
public sealed class WebUiOptionsTests
|
|
{
|
|
private static InstanceConfig Instanz(
|
|
bool enabled = true,
|
|
string binding = "loopback",
|
|
string token = "ein-hinreichend-langes-token",
|
|
int port = 7001)
|
|
=> new()
|
|
{
|
|
WebUiEnabled = enabled,
|
|
WebUiBinding = binding,
|
|
WebUiToken = token,
|
|
WebServerPort = port
|
|
};
|
|
|
|
[Fact]
|
|
public void Sie_ist_in_der_Vorbelegung_aus()
|
|
{
|
|
// Whoever wants a network service switches it on. Not the other way round.
|
|
new InstanceConfig().WebUiEnabled.ShouldBeFalse();
|
|
new InstanceConfig().WebUiBinding.ShouldBe("loopback");
|
|
new InstanceConfig().WebServerPort.ShouldBe(7001);
|
|
}
|
|
|
|
[Fact]
|
|
public void Abgeschaltet_ist_kein_Fehler()
|
|
{
|
|
WebUiOptions.TryCreate(Instanz(enabled: false), out var problem).ShouldBeNull();
|
|
problem.ShouldBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Ohne_Token_startet_sie_nicht_einmal_auf_Loopback()
|
|
{
|
|
// On a machine on which agents operate browser tools,
|
|
// "localhost" is no trust boundary.
|
|
WebUiOptions.TryCreate(Instanz(token: ""), out var problem).ShouldBeNull();
|
|
problem.ShouldNotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Alle_Adressen_ohne_Token_werden_abgelehnt_und_nicht_bemaengelt()
|
|
{
|
|
var options = WebUiOptions.TryCreate(Instanz(binding: "any", token: ""), out var problem);
|
|
|
|
options.ShouldBeNull();
|
|
problem.ShouldNotBeNull();
|
|
problem!.ShouldContain("So wird sie nicht gestartet");
|
|
}
|
|
|
|
[Fact]
|
|
public void Ein_zu_kurzes_Token_zaehlt_nicht()
|
|
{
|
|
WebUiOptions.TryCreate(Instanz(token: "kurz"), out var problem).ShouldBeNull();
|
|
problem.ShouldNotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Loopback_bindet_an_127_0_0_1()
|
|
{
|
|
var options = WebUiOptions.TryCreate(Instanz(port: 9001), out _);
|
|
|
|
options.ShouldNotBeNull();
|
|
options!.Url.ShouldBe("http://127.0.0.1:9001");
|
|
options.LoopbackOnly.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Alles_ausser_any_bleibt_Loopback()
|
|
{
|
|
// A typo in the instance file must not put the user interface onto the network.
|
|
WebUiOptions.TryCreate(Instanz(binding: "alle"), out _)!.LoopbackOnly.ShouldBeTrue();
|
|
WebUiOptions.TryCreate(Instanz(binding: ""), out _)!.LoopbackOnly.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Mit_Token_darf_sie_an_alle_Adressen()
|
|
{
|
|
var options = WebUiOptions.TryCreate(Instanz(binding: "ANY"), out _);
|
|
|
|
options.ShouldNotBeNull();
|
|
options!.LoopbackOnly.ShouldBeFalse();
|
|
options.Url.ShouldStartWith("http://0.0.0.0:");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-1)]
|
|
[InlineData(70000)]
|
|
public void Ein_unmoeglicher_Port_wird_abgelehnt(int port)
|
|
{
|
|
WebUiOptions.TryCreate(Instanz(port: port), out var problem).ShouldBeNull();
|
|
problem.ShouldNotBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Das_Token_steht_geschuetzt_in_der_Instanzdatei()
|
|
{
|
|
// Without the entry in ConfigSecrets it would be in plain text next to the
|
|
// protected OpenRouter key.
|
|
Core.Security.ConfigSecrets.IsSecretKey("webUiToken").ShouldBeTrue();
|
|
|
|
var config = Instanz(token: "ein-hinreichend-langes-token");
|
|
Core.Security.ConfigSecrets.Protect(config);
|
|
|
|
config.WebUiToken.ShouldNotBe("ein-hinreichend-langes-token");
|
|
|
|
Core.Security.ConfigSecrets.Unprotect(config);
|
|
config.WebUiToken.ShouldBe("ein-hinreichend-langes-token");
|
|
}
|
|
}
|