Forge
csharpdeeb25a2
1using System.Diagnostics;
2using System.Text.Json;
3
4namespace CascadeIDE.Features.Agent.Environment;
5
6/// <summary>
7/// <c>[agent.environment] shell_escape_tier</c> (ADR 0148): блокирует обход AEE через «сырые» MCP-команды
8/// <c>build</c>/<c>run_tests</c> (отдельный <c>dotnet</c> вне лестницы verify).
9/// </summary>
10public static class ShellEscapePolicy
11{
12 private static readonly JsonSerializerOptions JsonCompact = new() { WriteIndented = false };
13
14 /// <summary>Возвращает JSON-ошибку для MCP, если команда заблокирована.</summary>
15 public static string? TryBlockJson(string commandId, string? tier)
16 {
17 if (!IsBypassingAeeDotnetCommand(commandId))
18 return null;
19
20 var t = (tier ?? ShellEscapeTier.Deny).Trim();
21 if (string.Equals(t, ShellEscapeTier.AllowWithAudit, StringComparison.OrdinalIgnoreCase))
22 {
23 Trace.TraceInformation("[AEE] shell_escape_tier={0} command={1}", ShellEscapeTier.AllowWithAudit, commandId);
24 return null;
25 }
26
27 if (string.Equals(t, ShellEscapeTier.TestsOnly, StringComparison.OrdinalIgnoreCase))
28 {
29 if (IsTestOnlyCommand(commandId))
30 return null;
31
32 return BlockPayload(
33 tier: t,
34 commandId,
35 $"Tier {ShellEscapeTier.TestsOnly}: разрешены только run_tests/run_affected_tests; сборка/format — через ide_agent_verify или смените shell_escape_tier.");
36 }
37
38 if (string.Equals(t, ShellEscapeTier.Deny, StringComparison.OrdinalIgnoreCase))
39 return BlockPayload(
40 tier: t,
41 commandId,
42 "Tier deny: используйте ide_agent_verify с нужной политикой вместо прямых build/run_tests MCP.");
43
44 return BlockPayload(t, commandId, $"Неизвестный shell_escape_tier «{t}»; считается блокирующим.");
45 }
46
47 private static bool IsBypassingAeeDotnetCommand(string commandId) =>
48 commandId is IdeCommands.Build
49 or IdeCommands.BuildStructured
50 or IdeCommands.RunTests
51 or IdeCommands.RunAffectedTests
52 or IdeCommands.RunCodeCleanup;
53
54 private static bool IsTestOnlyCommand(string commandId) =>
55 commandId is IdeCommands.RunTests or IdeCommands.RunAffectedTests;
56
57 private static string BlockPayload(string tier, string commandId, string message) =>
58 JsonSerializer.Serialize(
59 new
60 {
61 error = "shell_escape_blocked",
62 shell_escape_tier = tier,
63 command_id = commandId,
64 message,
65 use_instead = "ide_agent_verify",
66 },
67 JsonCompact);
68}
69
View only · write via MCP/CIDE