0.27.0

Итерация P2 (часть): безопасность и расширение возможностей агента. Закрыты задачи docs/audit/P2/README.md: P2-S1, P2-S2, P2-S3, P2-M3, P2-T1.

Added

  • CSRF protection (P2-S1): новое middleware internal/server/middleware/csrf.go с double-submit token + Origin/Referer-проверкой. При /oauth/login устанавливается cookie tc_csrf (без HttpOnly) и токен возвращается в JSON-теле; на /oauth/authorize middleware требует совпадения cookie ↔ заголовка X-CSRF-Token (constant-time). 10 unit-тестов покрывают GET-bypass, отсутствие cookie/header, mismatch, Origin/Referer-проверку.
  • Ротация мастер-ключа шифрования (P2-S2): новый KeyManager в internal/secrets/keymanager.go — поддерживает active + retired keys, читает/пишет <dataDir>/keys.json. Методы Rotate(), PurgeRetired(), Decrypt() с автоматическим перебором ключей. Команда secrets.ReencryptAll() обходит settings, llm_providers и email_accounts. Admin-эндпоинты GET /api/v1/admin/secrets/status, POST /api/v1/admin/secrets/rotate, POST /api/v1/admin/secrets/reencrypt. 5 unit-тестов покрывают encrypt/rotate/purge/legacy-rejection.
  • Memory tools для агента (P2-M3): три новых инструмента в internal/agent/tools/memory.go:
  • memory_search — гибридный поиск (vector + FTS + RRF) по фактам с фильтром категории.
  • memory_remember — сохранение нового факта с дедупликацией (cosine ≥ 0.95).
  • memory_forget — деактивация факта по id (с проверкой scope). Регистрируются при perms.Tools.Memory = true. Все три работают строго в user-scope текущей сессии. 4 unit-теста (create/forget/cross-scope-reject/dedup).
  • Skills trigger-активация (P2-T1): новый файл internal/skills/triggers.go с типом SkillMetadata (хранится в Skill.Metadata как JSON, без миграции схемы). Поддерживаются паттерны kw:текст, regex:^..., plain (alias для kw:). Skills с непустым Triggers и совпавшим паттерном инжектятся как Triggered Skill в system prompt. SkillsHandler принимает triggers: []string в Create/Update и синхронизирует FS-конфиг. 13 unit-тестов покрывают match-логику и metadata roundtrip.

Changed

  • Dream user-scope (P2-S3): Dream.Run теперь принимает userID *int64 и работает строго в одном scope. Новый метод RunForAllScopes обходит общий scope (user_id IS NULL) и каждого пользователя агента отдельно. Все merge/update/deactivate-actions проверяются на cross-scope: попытка merge фактов разных пользователей блокируется с warning-логом. Курсоры теперь хранятся как dream_cursor:<agentID>:shared и dream_cursor:<agentID>:user:<userID>. DreamService.runOnce и MemoryHandler.RunDream обновлены на новый API. 3 unit-теста покрывают cross-scope reject и create-with-userID.
  • Legacy plaintext API-ключи (P2-S2): SettingsHandler.TestProvider больше не принимает незашифрованные значения из БД — возвращает 424 с просьбой переввести ключ через UI.
  • registerToolsForAgent теперь принимает userID *int64 для проброса в memory tools и согласованного user-scope.

Fixed

  • Dream merge утечка между пользователями (P2-S3): ранее Dream работал в admin-режиме с nil userID, что позволяло LLM предложить merge приватных фактов разных пользователей.