Task 26 — Least-privilege grants
Phase: 2
Status: done
Owner: —
Slug: least-privilege-grants
Goal
Навык получает только объявленные capabilities. Runtime проверяет grant при вызове; импорт навыка не может тихо расширить разрешения.
Acceptance criteria
Sub-tasks
LeastPrivilegeConfigвConfig/AppConfig.cs:Enabled(default true),EnforceOnImport(true),EnforceOnRuntime(true),MigrationMode(true),AllowedPermissions(list)SkillGrantrecord +GrantScopeenum +GrantValidationResult+GrantRequestвTools/Grants/Models.csISkillGrantServiceinterface +SkillGrantServiceimplementation:GrantAsync,RevokeAsync,RevokeByIdAsync,GetGrantsAsync,GetEffectivePermissionsAsync,CheckPermissionAsync,CheckAllPermissionsAsyncSkillGrantStore— SQLite persistence: таблицаskill_grants(id, skill_id, permission, scope, session_id, grantor, granted_at, expires_at) + indexesToolPolicyEngine— интеграцияISkillGrantService?; при tool execution проверяетCheckAllPermissionsAsync(skillId, requiredPermissions)и возвращает Denied если нет grantSkillPackager— при импорте: еслиEnforceOnImport=true, проверяет permissions навыка противAllowedPermissions; выбрасываетInvalidOperationExceptionесли ⊄GrantsController.cs— WebAPI:GET /api/grants/{skillId},POST /api/grants,DELETE /api/grants/{skillId},DELETE /api/grants/by-id/{id},GET /api/grants/{skillId}/checkProgram.cs(CLI + WebAPI) — DI:LeastPrivilegeConfig,SkillGrantStore,ISkillGrantService→SkillGrantService;ToolPolicyEngineполучаетISkillGrantServiceSkillGrantServiceTests.cs— 14 unit-тестов: grant, revoke, scope priority, missing permissions, migration mode, effective permissionsdotnet buildпроходит без warningsdotnet testпроходит (776/783; 7 pre-existing: OtelService × 5, BudgetGuard × 1, WasmTool × 1)
Implementation notes
2026-08-12
Добавлено:
src/agent/Tools/Grants/ — 4 новых файла:
Models.cs—GrantScopeenum (Skill/Session/Global),SkillGrantrecord,GrantValidationResult,GrantRequestISkillGrantService.cs— интерфейс с 7 методамиSkillGrantService.cs— реализация: SQLite-backed, проверяет grants по scope priority (Global > Session > Skill), migration mode (no grant = Read по умолчанию)SkillGrantStore.cs— IDisposable, sharedSqliteConnection, таблицаskill_grants+ 2 индекса
src/agent/Config/AppConfig.cs — LeastPrivilegeConfig:
Enabled,MigrationMode(true),EnforceOnImport(true),EnforceOnRuntime(true),AllowedPermissions(list)
src/agent/Tools/Policy/ToolPolicy.cs — PolicyContext.SkillId (nullable string)
src/agent/Tools/Policy/ToolPolicyEngine.cs — интеграция:
ISkillGrantService?nullable в конструкторе- В
Evaluate(): после permission check — grant check:CheckAllPermissionsAsync(skillId, requiredPermissions)→ Denied если нет grant
src/agent/Skills/SkillPackager.cs — интеграция grant validation:
- Новый конструктор с
LeastPrivilegeConfig+ISkillGrantService - В
Import(): еслиEnforceOnImport=trueи permissions не ⊆ AllowedPermissions →InvalidOperationException
src/agent/Agent/AgentCore.cs — передача SkillId в PolicyContext:
RunWithToolsAsyncпринимаетstring? skillIdпараметрPolicyContextполучаетSkillIdHandleAsyncCoreиEvaluateSkillAsyncпередаютroute.MatchedSkill?.Meta.Id
src/agent/Hercules.WebApi/Controllers/GrantsController.cs — 5 endpoints:
GET /api/grants/{skillId}— grants + session filterPOST /api/grants— выдать grantDELETE /api/grants/{skillId}— revokeDELETE /api/grants/by-id/{id}— revoke by grant IDGET /api/grants/{skillId}/check— check permission
DI (CLI + WebAPI): LeastPrivilegeConfig, SkillGrantStore, ISkillGrantService → SkillGrantService; ToolPolicyEngine получает ISkillGrantService
Tests: tests/.../Tools/Grants/SkillGrantServiceTests.cs — 14 тестов
Validation:
dotnet build Hercules.csproj— 0 errors, 0 warningsdotnet build Hercules.WebApi.csproj— 0 errors, 0 warningsdotnet test— 776/783 passed (7 pre-existing: OtelService × 5, BudgetGuard × 1, WasmTool × 1)
Scope / Likely files
src/agent/Tools/Grants/, src/agent/Skills/
Dependencies
- блокирует / опирается на: task_009 — tool-boundary-policy
- блокирует / опирается на: task_020 — skill-manifest
Risks / Rollback
Обратная совместимость со старыми навыками; миграционный режим.
Links
- Backlog: ../backlog.md
- Roadmap (EN): ../../ROADMAP-EN.md
- Roadmap (RU): ../../ROADMAP-RU.md