권한 기본값 Deny 정렬: 초기 정책/상태/슬래시 가이드 일치
Some checks failed
Release Gate / gate (push) Has been cancelled
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:
@@ -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 |
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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; } = "";
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
Reference in New Issue
Block a user