claw-code permissionSetup 비교 반영: 위험 자동허용 가드 + 회귀 테스트 추가
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
- 전역 권한이 Auto일 때 고위험 도구(process, spawn_agent, snippet_runner)는 자동 허용을 ask로 강등 - AgentContext 권한 계산 경로에 dangerous auto guard를 통합하여 우발적 무승인 실행 방지 - OperationModePolicyTests에 guard 동작 회귀 테스트 2건 추가 - 패리티 문서에 permissionSetup 기반 보강 항목 추가 - 로드맵/패리티 문서 테스트 수치 동기화: 374/374 - 검증: dotnet build 경고0 오류0, ParityBenchmark 12/12, ReplayStability 12/12, 전체 테스트 374/374
This commit is contained in:
@@ -102,4 +102,40 @@ public class OperationModePolicyTests
|
||||
allowed.Should().BeTrue();
|
||||
askCalled.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AgentContext_GetEffectiveToolPermission_DowngradesDangerousAutoToolWhenGlobalAuto()
|
||||
{
|
||||
var context = new AgentContext
|
||||
{
|
||||
Permission = "Auto",
|
||||
ToolPermissions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["process"] = "auto",
|
||||
}
|
||||
};
|
||||
|
||||
context.GetEffectiveToolPermission("process", "git status").Should().Be("ask");
|
||||
context.GetEffectiveToolPermission("file_read", @"E:\work\README.md").Should().Be("Auto");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AgentContext_CheckToolPermissionAsync_DangerousAutoToolRequiresPromptInGlobalAuto()
|
||||
{
|
||||
var askCalled = false;
|
||||
var context = new AgentContext
|
||||
{
|
||||
OperationMode = OperationModePolicy.ExternalMode,
|
||||
Permission = "Auto",
|
||||
AskPermission = (_, _) =>
|
||||
{
|
||||
askCalled = true;
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
};
|
||||
|
||||
var allowed = await context.CheckToolPermissionAsync("process", "git status");
|
||||
allowed.Should().BeFalse();
|
||||
askCalled.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,12 @@ public class AgentContext
|
||||
"process", "build_run", "git_tool", "http_tool", "open_external", "snippet_runner",
|
||||
"spawn_agent", "test_loop",
|
||||
};
|
||||
private static readonly HashSet<string> DangerousAutoTools = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"process",
|
||||
"spawn_agent",
|
||||
"snippet_runner",
|
||||
};
|
||||
|
||||
private readonly object _permissionLock = new();
|
||||
private readonly HashSet<string> _approvedPermissionCache = new(StringComparer.OrdinalIgnoreCase);
|
||||
@@ -191,22 +197,26 @@ public class AgentContext
|
||||
|
||||
public string GetEffectiveToolPermission(string toolName, string? target)
|
||||
{
|
||||
toolName ??= "";
|
||||
var normalizedToolName = toolName.Trim();
|
||||
|
||||
if (TryResolvePatternPermission(toolName, target, out var patternPermission))
|
||||
return PermissionModeCatalog.NormalizeToolOverride(patternPermission);
|
||||
return ApplyDangerousAutoGuard(normalizedToolName, PermissionModeCatalog.NormalizeToolOverride(patternPermission));
|
||||
|
||||
if (ToolPermissions.TryGetValue(toolName, out var toolPerm) &&
|
||||
!string.IsNullOrWhiteSpace(toolPerm))
|
||||
return PermissionModeCatalog.NormalizeToolOverride(toolPerm);
|
||||
return ApplyDangerousAutoGuard(normalizedToolName, PermissionModeCatalog.NormalizeToolOverride(toolPerm));
|
||||
if (ToolPermissions.TryGetValue("*", out var wildcardPerm) &&
|
||||
!string.IsNullOrWhiteSpace(wildcardPerm))
|
||||
return PermissionModeCatalog.NormalizeToolOverride(wildcardPerm);
|
||||
return ApplyDangerousAutoGuard(normalizedToolName, PermissionModeCatalog.NormalizeToolOverride(wildcardPerm));
|
||||
if (ToolPermissions.TryGetValue("default", out var defaultPerm) &&
|
||||
!string.IsNullOrWhiteSpace(defaultPerm))
|
||||
return PermissionModeCatalog.NormalizeToolOverride(defaultPerm);
|
||||
return ApplyDangerousAutoGuard(normalizedToolName, PermissionModeCatalog.NormalizeToolOverride(defaultPerm));
|
||||
|
||||
return SensitiveTools.Contains(toolName)
|
||||
var fallback = SensitiveTools.Contains(toolName)
|
||||
? PermissionModeCatalog.NormalizeGlobalMode(Permission)
|
||||
: PermissionModeCatalog.Auto;
|
||||
return ApplyDangerousAutoGuard(normalizedToolName, fallback);
|
||||
}
|
||||
|
||||
public async Task<bool> CheckToolPermissionAsync(string toolName, string target)
|
||||
@@ -297,6 +307,19 @@ public class AgentContext
|
||||
.Replace("\\?", ".") + "$";
|
||||
return Regex.IsMatch(input, regex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
}
|
||||
|
||||
private string ApplyDangerousAutoGuard(string toolName, string permission)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(toolName))
|
||||
return permission;
|
||||
|
||||
if (PermissionModeCatalog.IsAuto(permission)
|
||||
&& PermissionModeCatalog.IsAuto(Permission)
|
||||
&& DangerousAutoTools.Contains(toolName))
|
||||
return "ask";
|
||||
|
||||
return permission;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>에이전트 이벤트 (UI 표시용).</summary>
|
||||
|
||||
Reference in New Issue
Block a user