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>
115 lines
4.0 KiB
C#
115 lines
4.0 KiB
C#
using ClawdDotNet.Core.Instances;
|
|
using Shouldly;
|
|
|
|
namespace ClawdDotNet.Core.Tests.Instances;
|
|
|
|
/// <summary>
|
|
/// The proof that a licensed instance manager started the instance (#535).
|
|
///
|
|
/// <para><b>The hole this closes.</b> With E-M3 a managed instance no longer checks the license
|
|
/// itself — the manager did it centrally. What it recognized "managed" by was
|
|
/// the switch <c>--managed</c>, and a switch is no recognition.</para>
|
|
///
|
|
/// <para>The point is not to fend off someone who brings tools: the key
|
|
/// is in the executable. The point is that the ordinary way around the license
|
|
/// is closed.</para>
|
|
/// </summary>
|
|
public sealed class ManagerHandshakeTests
|
|
{
|
|
private const string Instanz = "/daten/Instances/Alpha";
|
|
private const string Andere = "/daten/Instances/Beta";
|
|
|
|
[Fact]
|
|
public void Eine_frische_Unterschrift_traegt()
|
|
{
|
|
var token = ManagerHandshake.Sign(Instanz);
|
|
|
|
ManagerHandshake.Verify(Instanz, token).ShouldBeTrue();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The case that was the occasion in the first place: <c>--managed</c> without a signature.
|
|
/// </summary>
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
[InlineData("--managed")]
|
|
[InlineData("v1")]
|
|
[InlineData("v1.999.")]
|
|
[InlineData("v2.99999999999.abcdef")]
|
|
[InlineData("v1.keinezahl.abcdef")]
|
|
public void Ohne_brauchbare_Unterschrift_gilt_die_Instanz_als_ungefuehrt(string? token)
|
|
{
|
|
ManagerHandshake.Verify(Instanz, token).ShouldBeFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// A made-up signature does not hold — even if the structure is right.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Eine_erfundene_Unterschrift_traegt_nicht()
|
|
{
|
|
var ablauf = DateTimeOffset.UtcNow.AddMinutes(5).ToUnixTimeSeconds();
|
|
|
|
ManagerHandshake.Verify(Instanz, $"v1.{ablauf}.{new string('a', 64)}")
|
|
.ShouldBeFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The check is against the directory the instance <b>actually</b> runs in.
|
|
///
|
|
/// <para>Otherwise one would sign the argument instead of the thing: a signature for
|
|
/// Alpha would let Beta start by presenting Alpha during the check.</para>
|
|
/// </summary>
|
|
[Fact]
|
|
public void Eine_Unterschrift_gilt_nur_fuer_ihre_eigene_Instanz()
|
|
{
|
|
var token = ManagerHandshake.Sign(Instanz);
|
|
|
|
ManagerHandshake.Verify(Andere, token).ShouldBeFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Expired is expired — otherwise someone would keep a signature and start
|
|
/// an instance without a license with it next week.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Eine_abgelaufene_Unterschrift_traegt_nicht()
|
|
{
|
|
var vorhin = DateTimeOffset.UtcNow.AddHours(-1);
|
|
var token = ManagerHandshake.Sign(Instanz, vorhin);
|
|
|
|
ManagerHandshake.Verify(Instanz, token, vorhin).ShouldBeTrue("Damals galt sie.");
|
|
ManagerHandshake.Verify(Instanz, token).ShouldBeFalse("Jetzt nicht mehr.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fiddling with the expiry time does not help: it goes into the signature.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Ein_verlaengerter_Ablauf_macht_die_Unterschrift_ungueltig()
|
|
{
|
|
var token = ManagerHandshake.Sign(Instanz);
|
|
var teile = token.Split('.');
|
|
|
|
var spaeter = DateTimeOffset.UtcNow.AddYears(1).ToUnixTimeSeconds();
|
|
|
|
ManagerHandshake.Verify(Instanz, $"v1.{spaeter}.{teile[2]}").ShouldBeFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The same path in a different spelling must yield the same signature — otherwise
|
|
/// the handshake fails because one wrote one slash more.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Schreibweisen_desselben_Pfades_ergeben_dieselbe_Unterschrift()
|
|
{
|
|
var basis = Path.Combine(Path.GetTempPath(), "clawd-handschlag");
|
|
var token = ManagerHandshake.Sign(basis);
|
|
|
|
ManagerHandshake.Verify(basis + Path.DirectorySeparatorChar, token).ShouldBeTrue();
|
|
ManagerHandshake.Verify(Path.Combine(basis, "."), token).ShouldBeTrue();
|
|
}
|
|
}
|