fix: diagnose blocked browser proxy policy
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
48387bd1bd
commit
17f377e04c
@ -435,6 +435,7 @@ Deliverables:
|
||||
- Dangerous command opt-in guidance: **implemented copyable safety guidance for camera/screen privacy-sensitive commands without emitting one-click dangerous repair commands**
|
||||
- Node capability settings: **implemented Settings toggles for canvas, screen, camera, location, and browser proxy command groups so privacy-sensitive surfaces can be disabled before reconnecting/re-pairing**
|
||||
- Disabled capability diagnostics: **implemented Command Center distinction between intentionally disabled Settings groups and true gateway allowlist/parity gaps**
|
||||
- Browser proxy policy diagnostics: **implemented a specific Command Center warning/copy action for declared `browser.proxy` commands filtered by gateway policy, instead of burying them under generic blocked-command output**
|
||||
|
||||
Risk: high for exec/security. Do not rush.
|
||||
|
||||
|
||||
@ -845,10 +845,12 @@ public class NodeCapabilityHealthInfo
|
||||
public Dictionary<string, bool> Permissions { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||
public List<string> SafeDeclaredCommands { get; set; } = new();
|
||||
public List<string> DangerousDeclaredCommands { get; set; } = new();
|
||||
public List<string> BrowserDeclaredCommands { get; set; } = new();
|
||||
public List<string> WindowsSpecificDeclaredCommands { get; set; } = new();
|
||||
public List<string> BlockedDeclaredCommands { get; set; } = new();
|
||||
public List<string> MissingSafeAllowlistCommands { get; set; } = new();
|
||||
public List<string> MissingDangerousAllowlistCommands { get; set; } = new();
|
||||
public List<string> MissingBrowserAllowlistCommands { get; set; } = new();
|
||||
public List<string> MissingMacParityCommands { get; set; } = new();
|
||||
public List<string> DisabledBySettingsCommands { get; set; } = new();
|
||||
public List<GatewayDiagnosticWarning> Warnings { get; set; } = new();
|
||||
@ -879,6 +881,9 @@ public class NodeCapabilityHealthInfo
|
||||
DangerousDeclaredCommands = CommandCenterCommandGroups.DangerousCommands
|
||||
.Where(commandSet.Contains)
|
||||
.ToList(),
|
||||
BrowserDeclaredCommands = CommandCenterCommandGroups.BrowserCommands
|
||||
.Where(commandSet.Contains)
|
||||
.ToList(),
|
||||
WindowsSpecificDeclaredCommands = CommandCenterCommandGroups.WindowsSpecificCommands
|
||||
.Where(commandSet.Contains)
|
||||
.ToList()
|
||||
@ -894,6 +899,8 @@ public class NodeCapabilityHealthInfo
|
||||
info.MissingSafeAllowlistCommands.Add(command);
|
||||
else if (CommandCenterCommandGroups.DangerousCommandSet.Contains(command))
|
||||
info.MissingDangerousAllowlistCommands.Add(command);
|
||||
else if (CommandCenterCommandGroups.BrowserCommandSet.Contains(command))
|
||||
info.MissingBrowserAllowlistCommands.Add(command);
|
||||
}
|
||||
|
||||
if (isWindows)
|
||||
@ -991,6 +998,14 @@ public static class CommandCenterCommandGroups
|
||||
public static readonly FrozenSet<string> DangerousCommandSet =
|
||||
DangerousCommands.ToFrozenSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public static readonly string[] BrowserCommands =
|
||||
[
|
||||
"browser.proxy"
|
||||
];
|
||||
|
||||
public static readonly FrozenSet<string> BrowserCommandSet =
|
||||
BrowserCommands.ToFrozenSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public static readonly string[] WindowsSpecificCommands =
|
||||
[
|
||||
"system.execApprovals.get",
|
||||
@ -1192,6 +1207,20 @@ public static class CommandCenterDiagnostics
|
||||
});
|
||||
}
|
||||
|
||||
if (node.MissingBrowserAllowlistCommands.Count > 0)
|
||||
{
|
||||
var blocked = string.Join(", ", node.MissingBrowserAllowlistCommands);
|
||||
warnings.Add(new GatewayDiagnosticWarning
|
||||
{
|
||||
Severity = GatewayDiagnosticSeverity.Warning,
|
||||
Category = "allowlist",
|
||||
Title = "Browser proxy command is filtered by gateway policy",
|
||||
Detail = $"{blocked} {(node.MissingBrowserAllowlistCommands.Count == 1 ? "is" : "are")} declared by the node but not allowed by gateway policy. Add the exact browser command and re-approve or re-pair the node if the gateway keeps an older command snapshot.",
|
||||
RepairAction = "Copy browser proxy allowlist repair command",
|
||||
CopyText = BuildAllowCommandsRepairCommand(node.MissingBrowserAllowlistCommands)
|
||||
});
|
||||
}
|
||||
|
||||
if (node.DisabledBySettingsCommands.Count > 0)
|
||||
{
|
||||
warnings.Add(new GatewayDiagnosticWarning
|
||||
@ -1205,7 +1234,8 @@ public static class CommandCenterDiagnostics
|
||||
|
||||
if (node.BlockedDeclaredCommands.Count > 0 &&
|
||||
node.MissingSafeAllowlistCommands.Count == 0 &&
|
||||
node.MissingDangerousAllowlistCommands.Count == 0)
|
||||
node.MissingDangerousAllowlistCommands.Count == 0 &&
|
||||
node.MissingBrowserAllowlistCommands.Count == 0)
|
||||
{
|
||||
warnings.Add(new GatewayDiagnosticWarning
|
||||
{
|
||||
|
||||
@ -693,11 +693,13 @@ public sealed partial class StatusDetailWindow : WindowEx
|
||||
builder.AppendLine($" declared commands: {FormatCommandList(node.Commands)}");
|
||||
builder.AppendLine($" safe companion commands: {FormatCommandList(node.SafeDeclaredCommands)}");
|
||||
builder.AppendLine($" privacy-sensitive opt-ins: {FormatCommandList(node.DangerousDeclaredCommands)}");
|
||||
builder.AppendLine($" browser proxy commands: {FormatCommandList(node.BrowserDeclaredCommands)}");
|
||||
builder.AppendLine($" Windows-specific commands: {FormatCommandList(node.WindowsSpecificDeclaredCommands)}");
|
||||
builder.AppendLine($" filtered by gateway policy: {FormatCommandList(node.BlockedDeclaredCommands)}");
|
||||
builder.AppendLine($" disabled in Settings: {FormatCommandList(node.DisabledBySettingsCommands)}");
|
||||
builder.AppendLine($" missing safe allowlist: {FormatCommandList(node.MissingSafeAllowlistCommands)}");
|
||||
builder.AppendLine($" missing privacy-sensitive allowlist: {FormatCommandList(node.MissingDangerousAllowlistCommands)}");
|
||||
builder.AppendLine($" missing browser proxy allowlist: {FormatCommandList(node.MissingBrowserAllowlistCommands)}");
|
||||
builder.AppendLine($" missing Mac parity: {FormatCommandList(node.MissingMacParityCommands)}");
|
||||
}
|
||||
|
||||
@ -842,6 +844,8 @@ public sealed partial class StatusDetailWindow : WindowEx
|
||||
parts.Add($"{node.SafeDeclaredCommands.Count} safe");
|
||||
if (node.DangerousDeclaredCommands.Count > 0)
|
||||
parts.Add($"{node.DangerousDeclaredCommands.Count} opt-in");
|
||||
if (node.BrowserDeclaredCommands.Count > 0)
|
||||
parts.Add("browser.proxy");
|
||||
if (node.WindowsSpecificDeclaredCommands.Count > 0)
|
||||
parts.Add($"{node.WindowsSpecificDeclaredCommands.Count} Windows");
|
||||
if (node.DisabledBySettingsCommands.Count > 0)
|
||||
@ -865,8 +869,10 @@ public sealed partial class StatusDetailWindow : WindowEx
|
||||
builder.AppendLine(BuildNodeSummary(node).TrimEnd());
|
||||
builder.AppendLine($"Safe companion commands: {FormatCommandList(node.SafeDeclaredCommands)}");
|
||||
builder.AppendLine($"Privacy-sensitive commands: {FormatCommandList(node.DangerousDeclaredCommands)}");
|
||||
builder.AppendLine($"Browser proxy commands: {FormatCommandList(node.BrowserDeclaredCommands)}");
|
||||
builder.AppendLine($"Windows-specific commands: {FormatCommandList(node.WindowsSpecificDeclaredCommands)}");
|
||||
builder.AppendLine($"Filtered by gateway policy: {FormatCommandList(node.BlockedDeclaredCommands)}");
|
||||
builder.AppendLine($"Missing browser proxy allowlist: {FormatCommandList(node.MissingBrowserAllowlistCommands)}");
|
||||
builder.AppendLine($"Disabled in Settings: {FormatCommandList(node.DisabledBySettingsCommands)}");
|
||||
builder.AppendLine($"Missing Mac parity: {FormatCommandList(node.MissingMacParityCommands)}");
|
||||
builder.AppendLine();
|
||||
|
||||
@ -918,6 +918,7 @@ public class CommandCenterModelTests
|
||||
Assert.Contains("device.info", CommandCenterCommandGroups.SafeCompanionCommands);
|
||||
Assert.Contains("device.status", CommandCenterCommandGroups.SafeCompanionCommands);
|
||||
Assert.Contains("screen.record", CommandCenterCommandGroups.DangerousCommands);
|
||||
Assert.Contains("browser.proxy", CommandCenterCommandGroups.BrowserCommands);
|
||||
Assert.Contains("browser.proxy", CommandCenterCommandGroups.MacNodeParityCommands);
|
||||
}
|
||||
|
||||
@ -1075,6 +1076,40 @@ public class CommandCenterModelTests
|
||||
!string.IsNullOrWhiteSpace(w.CopyText));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NodeCapabilityHealthInfo_WarnsSpecificallyForBlockedBrowserProxy()
|
||||
{
|
||||
var node = new GatewayNodeInfo
|
||||
{
|
||||
NodeId = "node-1",
|
||||
DisplayName = "Windows Node",
|
||||
Platform = "windows",
|
||||
IsOnline = true,
|
||||
Commands =
|
||||
[
|
||||
"system.notify",
|
||||
"system.run",
|
||||
"system.which",
|
||||
"browser.proxy"
|
||||
],
|
||||
Permissions = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["browser.proxy"] = false
|
||||
}
|
||||
};
|
||||
|
||||
var info = NodeCapabilityHealthInfo.FromNode(node);
|
||||
|
||||
Assert.Contains("browser.proxy", info.BrowserDeclaredCommands);
|
||||
Assert.Contains("browser.proxy", info.MissingBrowserAllowlistCommands);
|
||||
Assert.DoesNotContain("browser.proxy", info.MissingMacParityCommands);
|
||||
Assert.Contains(info.Warnings, w =>
|
||||
w.Title == "Browser proxy command is filtered by gateway policy" &&
|
||||
w.RepairAction == "Copy browser proxy allowlist repair command" &&
|
||||
w.CopyText == "openclaw config set gateway.nodes.allowCommands '[\"browser.proxy\"]'");
|
||||
Assert.DoesNotContain(info.Warnings, w => w.Title == "Some node commands are filtered");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NodeCapabilityHealthInfo_TreatsDisabledCommandsAsSettingsChoice()
|
||||
{
|
||||
|
||||
@ -176,6 +176,8 @@ public class TrayMenuWindowMarkupTests
|
||||
Assert.Contains("OpenClaw node inventory", source);
|
||||
Assert.Contains("Safe companion commands", source);
|
||||
Assert.Contains("Privacy-sensitive commands", source);
|
||||
Assert.Contains("Browser proxy commands", source);
|
||||
Assert.Contains("Missing browser proxy allowlist", source);
|
||||
Assert.Contains("Disabled in Settings", source);
|
||||
Assert.Contains("Missing Mac parity", source);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user