Files
ClawdDotNet/tests/ClawdDotNet.Core.Tests/Instances/ManagerHandshakeTests.cs
T
RichardandClaude Opus 5.5 77062facc9 Stufe 4c (#764): Bezeichner auf Englisch - Typen, Methoden, Felder, Parameter, Locals, Testnamen
Mit Roslyn umbenannt (Verweise folgen, Zeichenketten bleiben unberuehrt).
Nicht umbenannt, weil gespeichert oder ueber die API gebunden (Stufe 4e):
Properties, Record-Parameter, Enum-Member sowie die Parameter der
Endpunkt-Handler (Routen-/Query-Bindung ueber den Namen). Die JSON-Felder
anonymer Objekte bleiben ausdruecklich benannt (JsonFilter: pfad).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 13:18:43 +02:00

115 lines
3.9 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 InstanceDir = "/daten/Instances/Alpha";
private const string OtherDir = "/daten/Instances/Beta";
[Fact]
public void A_fresh_signature_holds()
{
var token = ManagerHandshake.Sign(InstanceDir);
ManagerHandshake.Verify(InstanceDir, 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 Without_a_usable_signature_the_instance_counts_as_unmanaged(string? token)
{
ManagerHandshake.Verify(InstanceDir, token).ShouldBeFalse();
}
/// <summary>
/// A made-up signature does not hold — even if the structure is right.
/// </summary>
[Fact]
public void A_forged_signature_does_not_hold()
{
var expiry = DateTimeOffset.UtcNow.AddMinutes(5).ToUnixTimeSeconds();
ManagerHandshake.Verify(InstanceDir, $"v1.{expiry}.{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 A_signature_is_only_valid_for_its_own_instance()
{
var token = ManagerHandshake.Sign(InstanceDir);
ManagerHandshake.Verify(OtherDir, 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 An_expired_signature_does_not_hold()
{
var earlier = DateTimeOffset.UtcNow.AddHours(-1);
var token = ManagerHandshake.Sign(InstanceDir, earlier);
ManagerHandshake.Verify(InstanceDir, token, earlier).ShouldBeTrue("Damals galt sie.");
ManagerHandshake.Verify(InstanceDir, token).ShouldBeFalse("Jetzt nicht mehr.");
}
/// <summary>
/// Fiddling with the expiry time does not help: it goes into the signature.
/// </summary>
[Fact]
public void An_extended_expiry_invalidates_the_signature()
{
var token = ManagerHandshake.Sign(InstanceDir);
var parts = token.Split('.');
var later = DateTimeOffset.UtcNow.AddYears(1).ToUnixTimeSeconds();
ManagerHandshake.Verify(InstanceDir, $"v1.{later}.{parts[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 Spellings_of_the_same_path_give_the_same_signature()
{
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();
}
}