feat: ship agent-first mission control v0.2.57
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Nexus.Api.Models;
|
||||
using Nexus.Api.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace Nexus.Api.Tests;
|
||||
|
||||
public sealed class OpenClawWizardServiceTests
|
||||
{
|
||||
private static readonly OpenClawInvocationContext Invocation =
|
||||
OpenClawInvocationContext.Create(
|
||||
actor: "owner-1",
|
||||
idempotencyKey: "wizard-test",
|
||||
correlationId: "wizard-correlation",
|
||||
traceParent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01");
|
||||
|
||||
[Fact]
|
||||
public async Task Start_RequiresExplicitConfirmationAndLocalManagement()
|
||||
{
|
||||
var gateway = ReadyGateway();
|
||||
var state = new OpenClawManagementState();
|
||||
var service = CreateService(gateway, state);
|
||||
|
||||
var unconfirmed = await service.StartAsync(
|
||||
new StartOpenClawWizardRequest(Confirmed: false),
|
||||
Invocation);
|
||||
var disabled = await service.StartAsync(
|
||||
new StartOpenClawWizardRequest(Confirmed: true),
|
||||
Invocation);
|
||||
|
||||
Assert.Equal("confirmation_required", unconfirmed.State);
|
||||
Assert.Equal("management_disabled", disabled.State);
|
||||
Assert.Empty(gateway.Invocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Start_UsesOfficialSafeParametersAndProjectsInteractiveStep()
|
||||
{
|
||||
var gateway = ReadyGateway();
|
||||
gateway.Handler = (method, _) => method == "wizard.start"
|
||||
? JsonNode.Parse(
|
||||
"""
|
||||
{
|
||||
"sessionId": "wizard-1",
|
||||
"done": false,
|
||||
"status": "running",
|
||||
"step": {
|
||||
"id": "mode",
|
||||
"type": "select",
|
||||
"title": "Choose mode",
|
||||
"options": [
|
||||
{ "value": "safe", "label": "Safe", "hint": "Recommended" }
|
||||
]
|
||||
}
|
||||
}
|
||||
""")
|
||||
: null;
|
||||
var state = new OpenClawManagementState();
|
||||
state.SetEnabled(true);
|
||||
var service = CreateService(gateway, state);
|
||||
|
||||
var result = await service.StartAsync(
|
||||
new StartOpenClawWizardRequest("remote", Confirmed: true),
|
||||
Invocation);
|
||||
|
||||
Assert.True(result.Ok);
|
||||
Assert.Equal("wizard-1", result.SessionId);
|
||||
Assert.Equal("select", result.Step?.Type);
|
||||
var invocation = Assert.Single(gateway.Invocations);
|
||||
Assert.Equal("wizard.start", invocation.Method);
|
||||
Assert.Equal("remote", invocation.Parameters?["mode"]?.GetValue<string>());
|
||||
Assert.False(invocation.Parameters?["installDaemon"]?.GetValue<bool>());
|
||||
Assert.Equal("setup", invocation.Parameters?["flow"]?.GetValue<string>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SensitiveStep_IsRedactedAndCannotBeAnsweredFromBrowser()
|
||||
{
|
||||
var gateway = ReadyGateway();
|
||||
gateway.Handler = (method, _) => method == "wizard.start"
|
||||
? JsonNode.Parse(
|
||||
"""
|
||||
{
|
||||
"sessionId": "wizard-secret",
|
||||
"done": false,
|
||||
"step": {
|
||||
"id": "provider-token",
|
||||
"type": "text",
|
||||
"title": "Provider token",
|
||||
"sensitive": true,
|
||||
"initialValue": "must-not-leak",
|
||||
"placeholder": "must-not-leak"
|
||||
}
|
||||
}
|
||||
""")
|
||||
: null;
|
||||
var state = new OpenClawManagementState();
|
||||
state.SetEnabled(true);
|
||||
var service = CreateService(gateway, state);
|
||||
|
||||
var started = await service.StartAsync(
|
||||
new StartOpenClawWizardRequest(Confirmed: true),
|
||||
Invocation);
|
||||
var advanced = await service.NextAsync(
|
||||
new AdvanceOpenClawWizardRequest(
|
||||
"wizard-secret",
|
||||
"provider-token",
|
||||
JsonValue.Create("browser-secret"),
|
||||
HasAnswer: true),
|
||||
Invocation);
|
||||
|
||||
Assert.True(started.Step?.Sensitive);
|
||||
Assert.Null(started.Step?.InitialValue);
|
||||
Assert.Null(started.Step?.Placeholder);
|
||||
Assert.False(started.Step?.CanAnswer);
|
||||
Assert.Equal("server_secret_required", advanced.State);
|
||||
Assert.Single(gateway.Invocations);
|
||||
Assert.DoesNotContain("must-not-leak", started.ToString(), StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("browser-secret", advanced.ToString(), StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static OpenClawWizardService CreateService(
|
||||
SetupGatewayConnector gateway,
|
||||
IOpenClawManagementState managementState)
|
||||
=> new(
|
||||
gateway,
|
||||
NullLogger<OpenClawWizardService>.Instance,
|
||||
managementState);
|
||||
|
||||
private static SetupGatewayConnector ReadyGateway()
|
||||
{
|
||||
var gateway = new SetupGatewayConnector
|
||||
{
|
||||
ConnectionState = GatewayConnectionState.Connected,
|
||||
GrantedScopes = new HashSet<string>(
|
||||
["operator.read", "operator.admin"],
|
||||
StringComparer.Ordinal),
|
||||
AdvertisedMethods = new HashSet<string>(
|
||||
["wizard.start", "wizard.next", "wizard.status", "wizard.cancel"],
|
||||
StringComparer.Ordinal)
|
||||
};
|
||||
return gateway;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user