feat: ship agent-first mission control v0.2.57
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Nexus.Api.Data;
|
||||
using Nexus.Api.Models;
|
||||
using Nexus.Api.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace Nexus.Api.Tests;
|
||||
|
||||
public sealed class OpenClawWriteGateTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Adopted_primary_profile_allows_matching_write_boundary()
|
||||
{
|
||||
var connector = ConnectedConnector();
|
||||
await using var fixture = await GateFixture.CreateAsync(connector);
|
||||
|
||||
var result = await fixture.Gate.EvaluateAsync("agents.create");
|
||||
|
||||
Assert.True(result.Allowed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Endpoint_change_after_adoption_blocks_write()
|
||||
{
|
||||
var connector = ConnectedConnector();
|
||||
await using var fixture = await GateFixture.CreateAsync(connector);
|
||||
connector.ActiveEndpoint = "wss://other-openclaw.example.test:18789/";
|
||||
|
||||
var result = await fixture.Gate.EvaluateAsync("agents.create");
|
||||
|
||||
Assert.False(result.Allowed);
|
||||
Assert.Equal("endpoint_trust_mismatch", result.State);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Device_change_after_adoption_blocks_write()
|
||||
{
|
||||
var connector = ConnectedConnector();
|
||||
await using var fixture = await GateFixture.CreateAsync(connector);
|
||||
connector.DeviceId = "unexpected-device";
|
||||
|
||||
var result = await fixture.Gate.EvaluateAsync("agents.create");
|
||||
|
||||
Assert.False(result.Allowed);
|
||||
Assert.Equal("device_trust_mismatch", result.State);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Wss_profile_without_tls_fingerprint_blocks_write()
|
||||
{
|
||||
var connector = ConnectedConnector();
|
||||
connector.ActiveTlsFingerprint = null;
|
||||
await using var fixture = await GateFixture.CreateAsync(connector);
|
||||
|
||||
var result = await fixture.Gate.EvaluateAsync("agents.create");
|
||||
|
||||
Assert.False(result.Allowed);
|
||||
Assert.Equal("tls_trust_missing", result.State);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Internal_ws_profile_without_tls_fingerprint_can_write()
|
||||
{
|
||||
var connector = ConnectedConnector();
|
||||
connector.ActiveEndpoint = "ws://openclaw-gateway:18789/";
|
||||
connector.ActiveTlsFingerprint = null;
|
||||
await using var fixture = await GateFixture.CreateAsync(connector);
|
||||
|
||||
var result = await fixture.Gate.EvaluateAsync("agents.create");
|
||||
|
||||
Assert.True(result.Allowed);
|
||||
}
|
||||
|
||||
private static StubOpenClawConnector ConnectedConnector()
|
||||
=> new()
|
||||
{
|
||||
ConnectionState = GatewayConnectionState.Connected,
|
||||
GatewayVersion = "2026.8.0",
|
||||
RequiredVersion = "2026.8.0",
|
||||
ProtocolVersion = 4,
|
||||
ActiveEndpoint = "wss://openclaw.example.test:18789/",
|
||||
ActiveTlsFingerprint = new string('A', 64),
|
||||
DeviceId = "nexus-device",
|
||||
GrantedScopes = new HashSet<string>(
|
||||
["operator.read", "operator.admin"],
|
||||
StringComparer.Ordinal),
|
||||
AdvertisedMethods = new HashSet<string>(
|
||||
["agents.create"],
|
||||
StringComparer.Ordinal),
|
||||
AdvertisedEvents = new HashSet<string>(
|
||||
["agent.updated"],
|
||||
StringComparer.Ordinal)
|
||||
};
|
||||
|
||||
private sealed class GateFixture(
|
||||
ServiceProvider provider,
|
||||
OpenClawWriteGate gate) : IAsyncDisposable
|
||||
{
|
||||
public OpenClawWriteGate Gate { get; } = gate;
|
||||
|
||||
public static async Task<GateFixture> CreateAsync(
|
||||
StubOpenClawConnector connector)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var databaseName = $"write-gate-{Guid.NewGuid():N}";
|
||||
services.AddDbContext<NexusDbContext>(options =>
|
||||
options.UseInMemoryDatabase(databaseName));
|
||||
var provider = services.BuildServiceProvider();
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
["OpenClawSetup:ExternalClientIdentitySupported"] = "true"
|
||||
})
|
||||
.Build();
|
||||
var options = Options.Create(new GatewayConnectorOptions
|
||||
{
|
||||
ClientId = "nexus",
|
||||
ClientMode = "backend",
|
||||
ExternalClientIdentitySupported = true,
|
||||
AllowReservedInternalClientIdentity = false
|
||||
});
|
||||
|
||||
await using (var scope = provider.CreateAsyncScope())
|
||||
{
|
||||
var db = scope.ServiceProvider
|
||||
.GetRequiredService<NexusDbContext>();
|
||||
db.OpenClawConnectionProfiles.Add(
|
||||
new OpenClawConnectionProfile
|
||||
{
|
||||
Endpoint = connector.ActiveEndpoint!,
|
||||
DiscoverySource = "test",
|
||||
RequiredVersion = connector.GatewayVersion,
|
||||
TlsCertificateFingerprint =
|
||||
connector.ActiveTlsFingerprint,
|
||||
AdoptionState = OpenClawAdoptionStates.Adopted,
|
||||
ManagementEnabled = true,
|
||||
CapabilityHash =
|
||||
OpenClawWriteGate.BuildCapabilityHash(connector),
|
||||
DeviceId = connector.DeviceId,
|
||||
Revision = 1
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return new GateFixture(
|
||||
provider,
|
||||
new OpenClawWriteGate(
|
||||
provider.GetRequiredService<IServiceScopeFactory>(),
|
||||
connector,
|
||||
options,
|
||||
configuration));
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync() => provider.DisposeAsync();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user