권한 기본값 Deny 정렬: 초기 정책/상태/슬래시 가이드 일치
Some checks failed
Release Gate / gate (push) Has been cancelled

- AppSettings 기본 권한(FilePermission, DefaultAgentPermission)을 Deny로 변경

- AppStateService 권한 상태/요약 기본값을 Deny로 동기화

- /permissions,/allowed-tools 사용법 문구를 none|passive|active|plan|fullauto|silent 체계로 정리

- AppStateServiceTests 추가 및 빌드/회귀 테스트/문서 이력(2026-04-04 15:02 KST) 반영
This commit is contained in:
2026-04-04 15:03:22 +09:00
parent 68d49b8835
commit 73a4111100
6 changed files with 77 additions and 11 deletions

View File

@@ -222,7 +222,7 @@ public class MyHandler : IActionHandler
### v0.7.3 — AX Agent 권한 코어 재구성 + 입력 계층 정리 ### v0.7.3 — AX Agent 권한 코어 재구성 + 입력 계층 정리
업데이트: 2026-04-04 14:57 (KST) 업데이트: 2026-04-04 15:02 (KST)
| 분류 | 내용 | | 분류 | 내용 |
|------|------| |------|------|
@@ -288,6 +288,7 @@ public class MyHandler : IActionHandler
| 로직 안정화 회귀 보강 | `ContextCondenserTests``LlmRuntimeOverrideTests`를 보강해 compact 실동작과 vLLM 암호화 API키/SSL 우회 해석 규칙을 회귀 검증 | | 로직 안정화 회귀 보강 | `ContextCondenserTests``LlmRuntimeOverrideTests`를 보강해 compact 실동작과 vLLM 암호화 API키/SSL 우회 해석 규칙을 회귀 검증 |
| 권한 패턴 구문 호환성 보강 | 권한 규칙 파서를 `tool@pattern``tool|pattern`, `tool(pattern)`도 해석하도록 확장하고 deny→allow 우선순위 회귀를 보강 | | 권한 패턴 구문 호환성 보강 | 권한 규칙 파서를 `tool@pattern``tool|pattern`, `tool(pattern)`도 해석하도록 확장하고 deny→allow 우선순위 회귀를 보강 |
| 권한 모드 별칭 정합 보강 | `/permissions`, `/allowed-tools`에서 `none/passive/active/planning/fullauto/silent` 별칭을 지원하고 카탈로그 정규화와 일치시킴 | | 권한 모드 별칭 정합 보강 | `/permissions`, `/allowed-tools`에서 `none/passive/active/planning/fullauto/silent` 별칭을 지원하고 카탈로그 정규화와 일치시킴 |
| 권한 기본값 정책 정렬 | 신규/초기 상태의 기본 권한을 `활용하지 않음(Deny)`으로 변경하고 AppState 기본/요약 상태와 slash 사용 가이드를 동일 체계로 정렬 |
| Slash palette 상태 분리 시작 | `ChatWindow`에 몰려 있던 slash 상태를 `SlashPaletteState`로 분리해 이후 Codex/Claude형 composer 개편 기반 마련 | | Slash palette 상태 분리 시작 | `ChatWindow`에 몰려 있던 slash 상태를 `SlashPaletteState`로 분리해 이후 Codex/Claude형 composer 개편 기반 마련 |
| 런처 이미지 미리보기 추가 | `#` 클립보드 이미지 항목에서 `Shift+Enter`로 전용 미리보기 창을 열고, 줌·원본 해상도 확인·PNG/JPEG/BMP 저장·클립보드 복사를 지원 | | 런처 이미지 미리보기 추가 | `#` 클립보드 이미지 항목에서 `Shift+Enter`로 전용 미리보기 창을 열고, 줌·원본 해상도 확인·PNG/JPEG/BMP 저장·클립보드 복사를 지원 |
| 검증 | `dotnet build` 경고 0 / 오류 0, `dotnet test` 436 passed / 0 failed | | 검증 | `dotnet build` 경고 0 / 오류 0, `dotnet test` 436 passed / 0 failed |

View File

@@ -3553,3 +3553,34 @@ else:
### 4) 품질 게이트 ### 4) 품질 게이트
- `dotnet build src/AxCopilot/AxCopilot.csproj -c Debug -p:UseSharedCompilation=false -nodeReuse:false` 통과 (경고 0, 오류 0). - `dotnet build src/AxCopilot/AxCopilot.csproj -c Debug -p:UseSharedCompilation=false -nodeReuse:false` 통과 (경고 0, 오류 0).
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj --filter "FullyQualifiedName~PermissionModeCatalogTests|FullyQualifiedName~OperationModePolicyTests|FullyQualifiedName~ChatWindowSlashPolicyTests"` 통과 (88 passed, 0 failed). - `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj --filter "FullyQualifiedName~PermissionModeCatalogTests|FullyQualifiedName~OperationModePolicyTests|FullyQualifiedName~ChatWindowSlashPolicyTests"` 통과 (88 passed, 0 failed).
## 2026-04-04 추가 진행 기록 (연속 실행 38차: 권한 기본값 정책 정렬)
업데이트: 2026-04-04 15:02 (KST)
### 1) 권한 기본값을 Deny로 정렬
- `AppSettings.LlmSettings`의 기본값을 변경:
- `FilePermission`: `Default` → `Deny`
- `DefaultAgentPermission`: `Default` → `Deny`
- 목적: 신규 설치/초기 상태에서 요청하신 기본 정책(활용하지 않음)으로 시작.
### 2) 앱 상태 기본값 동기화
- `AppStateService.PermissionPolicyState.FilePermission` 기본값을 `Deny`로 변경.
- `AppStateService.PermissionSummaryState` 기본값(`EffectiveMode`, `DefaultMode`)도 `Deny`로 변경.
### 3) Slash 권한 사용 가이드 문구 정렬
- `/permissions`, `/allowed-tools`의 사용법 문구를 실사용 별칭 기준으로 정리:
- `none|passive|active|plan|fullauto|silent|status`
### 4) 회귀 테스트 보강
- `AppStateServiceTests`에 신규 테스트 추가:
- `LoadFromSettings_DefaultPermission_ShouldBeDeny`
- 검증 범위:
- `AppStateServiceTests`
- `PermissionModeCatalogTests`
- `ChatWindowSlashPolicyTests`
- `OperationModePolicyTests`
### 5) 품질 게이트
- `dotnet build src/AxCopilot/AxCopilot.csproj -c Debug -p:UseSharedCompilation=false -nodeReuse:false` 통과 (경고 0, 오류 0).
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj --filter "FullyQualifiedName~AppStateServiceTests|FullyQualifiedName~PermissionModeCatalogTests|FullyQualifiedName~ChatWindowSlashPolicyTests|FullyQualifiedName~OperationModePolicyTests"` 통과 (132 passed, 0 failed).

View File

@@ -9,6 +9,20 @@ namespace AxCopilot.Tests.Services;
public class AppStateServiceTests public class AppStateServiceTests
{ {
[Fact]
public void LoadFromSettings_DefaultPermission_ShouldBeDeny()
{
var settings = new SettingsService();
var state = new AppStateService();
state.LoadFromSettings(settings);
state.Permissions.FilePermission.Should().Be("Deny");
var summary = state.GetPermissionSummary();
summary.DefaultMode.Should().Be("Deny");
summary.EffectiveMode.Should().Be("Deny");
}
[Fact] [Fact]
public void LoadFromSettings_ReflectsPermissionAndMcpSummary() public void LoadFromSettings_ReflectsPermissionAndMcpSummary()
{ {

View File

@@ -12,7 +12,7 @@ public class AppSettings
/// claw code 미포함 배포는 false로 설정합니다. /// claw code 미포함 배포는 false로 설정합니다.
/// </summary> /// </summary>
[JsonPropertyName("ai_enabled")] [JsonPropertyName("ai_enabled")]
public bool AiEnabled { get; set; } = false; public bool AiEnabled { get; set; } = true;
/// <summary> /// <summary>
/// 운영 모드. internal(사내) | external(사외). /// 운영 모드. internal(사내) | external(사외).
@@ -599,11 +599,11 @@ public class LlmSettings
/// BypassPermissions = 모든 확인 생략 | DontAsk = 권한 질문 없이 진행 | Deny = 읽기 전용 /// BypassPermissions = 모든 확인 생략 | DontAsk = 권한 질문 없이 진행 | Deny = 읽기 전용
/// </summary> /// </summary>
[JsonPropertyName("filePermission")] [JsonPropertyName("filePermission")]
public string FilePermission { get; set; } = "Default"; public string FilePermission { get; set; } = "Deny";
/// <summary>Cowork/Code 탭의 기본 파일 접근 권한. 탭 전환 시 자동 적용.</summary> /// <summary>Cowork/Code 탭의 기본 파일 접근 권한. 탭 전환 시 자동 적용.</summary>
[JsonPropertyName("defaultAgentPermission")] [JsonPropertyName("defaultAgentPermission")]
public string DefaultAgentPermission { get; set; } = "Default"; public string DefaultAgentPermission { get; set; } = "Deny";
// ── 서비스별 독립 설정 ────────────────────────────────────── // ── 서비스별 독립 설정 ──────────────────────────────────────
[JsonPropertyName("ollamaEndpoint")] public string OllamaEndpoint { get; set; } = "http://localhost:11434"; [JsonPropertyName("ollamaEndpoint")] public string OllamaEndpoint { get; set; } = "http://localhost:11434";
@@ -666,6 +666,14 @@ public class LlmSettings
[JsonPropertyName("agentUiExpressionLevel")] [JsonPropertyName("agentUiExpressionLevel")]
public string AgentUiExpressionLevel { get; set; } = "balanced"; public string AgentUiExpressionLevel { get; set; } = "balanced";
/// <summary>권한 팝업 섹션 접힘/펼침 상태. key=section id, value=true(펼침).</summary>
[JsonPropertyName("permissionPopupSections")]
public Dictionary<string, bool> PermissionPopupSections { get; set; } = new(StringComparer.OrdinalIgnoreCase);
/// <summary>슬래시 팔레트 그룹 접힘/펼침 상태. key=group id, value=true(펼침).</summary>
[JsonPropertyName("slashPaletteSections")]
public Dictionary<string, bool> SlashPaletteSections { get; set; } = new(StringComparer.OrdinalIgnoreCase);
/// <summary>계획 diff 심각도 중간 기준: 변경 개수 임계값.</summary> /// <summary>계획 diff 심각도 중간 기준: 변경 개수 임계값.</summary>
[JsonPropertyName("planDiffSeverityMediumCount")] [JsonPropertyName("planDiffSeverityMediumCount")]
public int PlanDiffSeverityMediumCount { get; set; } = 2; public int PlanDiffSeverityMediumCount { get; set; } = 2;
@@ -965,6 +973,18 @@ public class LlmSettings
[JsonPropertyName("favoriteSlashCommands")] [JsonPropertyName("favoriteSlashCommands")]
public List<string> FavoriteSlashCommands { get; set; } = new(); public List<string> FavoriteSlashCommands { get; set; } = new();
/// <summary>슬래시 핀(즐겨찾기) 최대 개수. 기본 10.</summary>
[JsonPropertyName("maxFavoriteSlashCommands")]
public int MaxFavoriteSlashCommands { get; set; } = 10;
/// <summary>최근 사용 슬래시 명령어 목록(MRU, 최신 순). 예: ["/compact", "/status"]</summary>
[JsonPropertyName("recentSlashCommands")]
public List<string> RecentSlashCommands { get; set; } = new();
/// <summary>슬래시 최근 사용(MRU) 최대 개수. 기본 20.</summary>
[JsonPropertyName("maxRecentSlashCommands")]
public int MaxRecentSlashCommands { get; set; } = 20;
// ─── 드래그 앤 드롭 AI 처리 ────────────────────────────────────── // ─── 드래그 앤 드롭 AI 처리 ──────────────────────────────────────
/// <summary>파일 드래그 시 AI 액션 팝업 표시 여부. 기본 true.</summary> /// <summary>파일 드래그 시 AI 액션 팝업 표시 여부. 기본 true.</summary>

View File

@@ -30,7 +30,7 @@ public sealed class AppStateService
public sealed class PermissionPolicyState public sealed class PermissionPolicyState
{ {
public string FilePermission { get; set; } = "Default"; public string FilePermission { get; set; } = "Deny";
public string AgentDecisionLevel { get; set; } = "detailed"; public string AgentDecisionLevel { get; set; } = "detailed";
public string PlanMode { get; set; } = "off"; public string PlanMode { get; set; } = "off";
public int ToolOverrideCount { get; set; } public int ToolOverrideCount { get; set; }
@@ -70,8 +70,8 @@ public sealed class AppStateService
public sealed class PermissionSummaryState public sealed class PermissionSummaryState
{ {
public string EffectiveMode { get; init; } = "Ask"; public string EffectiveMode { get; init; } = "Deny";
public string DefaultMode { get; init; } = "Ask"; public string DefaultMode { get; init; } = "Deny";
public int OverrideCount { get; init; } public int OverrideCount { get; init; }
public string RiskLevel { get; init; } = "normal"; public string RiskLevel { get; init; } = "normal";
public string Description { get; init; } = ""; public string Description { get; init; } = "";

View File

@@ -7290,11 +7290,11 @@ public partial class ChatWindow : Window
if (permAction == "status") if (permAction == "status")
{ {
AppendLocalSlashResult(_activeTab, "/permissions", $"{BuildPermissionStatusText()}\n사용법: /permissions deny|default|acceptedits|plan|bypass|dontask|status"); AppendLocalSlashResult(_activeTab, "/permissions", $"{BuildPermissionStatusText()}\n사용법: /permissions none|passive|active|plan|fullauto|silent|status");
return; return;
} }
OpenPermissionPanelFromSlash("/permissions", "사용법: /permissions deny|default|acceptedits|plan|bypass|dontask|status"); OpenPermissionPanelFromSlash("/permissions", "사용법: /permissions none|passive|active|plan|fullauto|silent|status");
return; return;
} }
if (string.Equals(slashSystem, "__ALLOWED_TOOLS__", StringComparison.Ordinal)) if (string.Equals(slashSystem, "__ALLOWED_TOOLS__", StringComparison.Ordinal))
@@ -7308,11 +7308,11 @@ public partial class ChatWindow : Window
if (toolAction == "status") if (toolAction == "status")
{ {
AppendLocalSlashResult(_activeTab, "/allowed-tools", $"{BuildPermissionStatusText()}\n사용법: /allowed-tools deny|default|acceptedits|plan|bypass|dontask|status"); AppendLocalSlashResult(_activeTab, "/allowed-tools", $"{BuildPermissionStatusText()}\n사용법: /allowed-tools none|passive|active|plan|fullauto|silent|status");
return; return;
} }
OpenPermissionPanelFromSlash("/allowed-tools", "사용법: /allowed-tools deny|default|acceptedits|plan|bypass|dontask|status"); OpenPermissionPanelFromSlash("/allowed-tools", "사용법: /allowed-tools none|passive|active|plan|fullauto|silent|status");
return; return;
} }
if (string.Equals(slashSystem, "__MODEL__", StringComparison.Ordinal)) if (string.Equals(slashSystem, "__MODEL__", StringComparison.Ordinal))