using Fleet.Core; using Fleet.Hosting; using Fleet.Identity; namespace Fleet.Tests; /// 节点自己要求有属主(passkey):Agent 和 Probe 共用这一份,没有属主就不运行。 public sealed class OwnerGuardTests : IDisposable { private readonly TestAuthenticator _alice = new(); private readonly string _directory = Path.Combine(Path.GetTempPath(), "moshiro-owner-" + Guid.NewGuid().ToString("N")); public OwnerGuardTests() { Directory.CreateDirectory(_directory); } public void Dispose() { _alice.Dispose(); Directory.Delete(_directory, recursive: true); } private void Pin(params string[] controllers) { var set = new OperatorSet(1, OperatorTrust.Genesis, TestAuthenticator.RpId, [TestAuthenticator.Origin], [_alice.Key]); SignedStatement genesis = _alice.Sign(OperatorTrust.Encode(set)); TrustAnchor.Pin(_directory, OperatorTrust.Fingerprint(genesis.Statement), [genesis.ToDto()], controllers); } [Fact] public void ANodeEnrolledWithoutATrustRoot_HasNoOwner_AndDoesNotRun() { TrustAnchor none = TrustAnchor.Load(_directory, NullNodeLog.Instance); Assert.NotNull(OwnerGuard.Problem(none, require: true)); Assert.False(OwnerGuard.Check(_directory, require: true, NullNodeLog.Instance)); } [Fact] public void ANodePinnedToAnOwnerPasskey_Runs() { Pin(_alice.CredentialId); TrustAnchor pinned = TrustAnchor.Load(_directory, NullNodeLog.Instance); Assert.Null(OwnerGuard.Problem(pinned, require: true)); Assert.True(OwnerGuard.Check(_directory, require: true, NullNodeLog.Instance)); Assert.Equal([_alice.CredentialId], pinned.Controllers); } [Fact] public void APinnedNodeWhoseOwnerIsNoLongerInTheOperatorSet_DoesNotRun() { Pin("some-passkey-that-is-not-in-the-set"); TrustAnchor pinned = TrustAnchor.Load(_directory, NullNodeLog.Instance); Assert.Empty(pinned.Controllers); Assert.NotNull(OwnerGuard.Problem(pinned, require: true)); } [Fact] public void TheRequirementCanBeTurnedOff_ForAPanelWithoutATrustRoot() { TrustAnchor none = TrustAnchor.Load(_directory, NullNodeLog.Instance); Assert.Null(OwnerGuard.Problem(none, require: false)); } }