From 2d43db69c911af51fce185f092c45f2a71a66f19 Mon Sep 17 00:00:00 2001 From: "a.tolmachev" Date: Sun, 3 May 2026 10:38:12 +0000 Subject: [PATCH] docs: align agent auth model and fix session test --- .gitignore | 2 +- TASKS.md | 13 ++ apps/mcp-server/src/session.rs | 16 +- docs/admin-api.md | 49 +++-- docs/agent-auth-model.md | 281 +++++++++++++++++++++++++++++ docs/alpine-ui-integration-plan.md | 5 + docs/architecture.md | 33 +++- docs/as-is-to-be.md | 6 + docs/backend-gap-plan.md | 5 + docs/data-model.md | 61 ++++++- docs/database-schema.md | 85 ++++++++- docs/diagrams.md | 6 + docs/implementation-plan.md | 44 +++-- docs/mcp-interface.md | 27 ++- docs/module-decomposition.md | 6 +- 15 files changed, 578 insertions(+), 61 deletions(-) create mode 100644 docs/agent-auth-model.md diff --git a/.gitignore b/.gitignore index c3e88a2..bbc2aba 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ apps/ui/vite.config.js apps/ui/vite.config.d.ts *.log __*.md -diplom.docx +diploma/ diff --git a/TASKS.md b/TASKS.md index fe195a0..b45e765 100644 --- a/TASKS.md +++ b/TASKS.md @@ -2,6 +2,19 @@ ## Current +### `feat/agent-scoped-machine-auth` + +Status: ready + +DoD: +- AI agent can receive its own long-lived agent key from the admin UI +- operation has an explicit security level: `standard`, `elevated`, or `strict` +- machine calls to MCP can use short-lived agent tokens for elevated operations +- one-time token mode is defined for strict operations +- transition path from workspace-wide keys is explicit in docs and implementation slices + +## Next + ### `feat/live-authenticated-staging-entry` Status: ready diff --git a/apps/mcp-server/src/session.rs b/apps/mcp-server/src/session.rs index 06b1ebf..83134db 100644 --- a/apps/mcp-server/src/session.rs +++ b/apps/mcp-server/src/session.rs @@ -340,7 +340,7 @@ mod tests { Executor, postgres::{PgConnectOptions, PgPoolOptions}, }; - use time::format_description::well_known::Rfc3339; + use time::{OffsetDateTime, format_description::well_known::Rfc3339}; use uuid::Uuid; use super::{ @@ -353,6 +353,12 @@ mod tests { time::OffsetDateTime::parse(value, &Rfc3339).unwrap() } + fn truncate_to_micros(value: OffsetDateTime) -> OffsetDateTime { + value + .replace_nanosecond((value.nanosecond() / 1_000) * 1_000) + .unwrap() + } + #[tokio::test] async fn creates_and_reads_transport_sessions() { let store = InMemorySessionStore::default(); @@ -455,15 +461,15 @@ mod tests { .await .unwrap(); - let created_at = timestamp("2026-05-01T10:00:00Z"); - let initialized_at = timestamp("2026-05-01T10:00:05Z"); + let created_at = OffsetDateTime::now_utc() - time::Duration::hours(1); + let initialized_at = created_at + time::Duration::seconds(5); let session_id = store_a .create( "2025-11-25", "default", "sales", created_at, - Some(timestamp("2026-05-02T10:00:00Z")), + Some(created_at + time::Duration::days(30)), ) .await .unwrap(); @@ -482,7 +488,7 @@ mod tests { assert_eq!(session.id, session_id); assert!(session.initialized); - assert_eq!(session.updated_at, initialized_at); + assert_eq!(session.updated_at, truncate_to_micros(initialized_at)); assert_eq!(session.workspace_slug, "default"); assert_eq!(session.agent_slug, "sales"); } diff --git a/docs/admin-api.md b/docs/admin-api.md index e3cf3e3..a4fa743 100644 --- a/docs/admin-api.md +++ b/docs/admin-api.md @@ -2,7 +2,7 @@ ## 1. Назначение документа -Этот документ фиксирует целевые HTTP-контракты административного API, через которое UI управляет workspace, operations, agents, platform access и observability. +Этот документ фиксирует целевые HTTP-контракты административного API, через которое UI управляет workspace, operations, agents, machine access и observability. Для потоковой модели детальные HTTP DTO вынесены отдельно в: @@ -33,7 +33,7 @@ - `secrets` - `auth-profiles` - `agents` -- `platform-api-keys` +- `agent-keys` - `logs` - `usage` - `samples` @@ -110,6 +110,12 @@ - `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}/export` - `POST /api/admin/workspaces/{workspace_id}/operations/import` +Контракт дополнительно включает: + +- у операции задается обязательный `security_level`; +- допустимые значения: `standard`, `elevated`, `strict`; +- этот параметр определяет минимально допустимый режим машинного доступа при вызове через MCP. + ### 5.4. Samples and descriptors - `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/samples/input-json` @@ -169,20 +175,32 @@ - `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/archive` - `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/bindings` - `DELETE /api/admin/workspaces/{workspace_id}/agents/{agent_id}/bindings/{operation_id}` - -### 5.7. Platform API keys - -- `GET /api/admin/workspaces/{workspace_id}/platform-api-keys` -- `POST /api/admin/workspaces/{workspace_id}/platform-api-keys` -- `POST /api/admin/workspaces/{workspace_id}/platform-api-keys/{key_id}/revoke` -- `DELETE /api/admin/workspaces/{workspace_id}/platform-api-keys/{key_id}` +- `GET /api/admin/workspaces/{workspace_id}/agents/{agent_id}/keys` +- `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/keys` +- `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/keys/{key_id}/revoke` +- `DELETE /api/admin/workspaces/{workspace_id}/agents/{agent_id}/keys/{key_id}` Контракт: -- `POST /platform-api-keys` возвращает metadata ключа и одноразовый `secret`; -- `secret` доступен только в create-response; -- list endpoints возвращают только metadata, `prefix`, `status`, `scopes` и `last_used_at`. -- `last_used_at` обновляется при успешной machine-auth аутентификации этим ключом в `mcp-server`. +- `POST /agents/{agent_id}/keys` возвращает metadata ключа и одноразовый `secret`; +- полное значение ключа доступно только в create-response; +- list endpoints возвращают только metadata, `prefix`, `status`, `scopes`, `expires_at` и `last_used_at`; +- ключ агента принадлежит одному `agent` и не должен использоваться как основной рабочий токен вызова в целевой защищенной схеме; +- ключ агента используется для получения короткоживущего токена доступа к MCP endpoint. + +### 5.7. Token issuance + +Для расширенных редакций платформы: + +- `POST /mcp-auth/v1/token` +- `POST /mcp-auth/v1/token/one-time` + +Контракт: + +- `POST /mcp-auth/v1/token` выдает короткоживущий токен доступа для операций уровня `elevated`; +- `POST /mcp-auth/v1/token/one-time` выдает одноразовый токен для операций уровня `strict`; +- открытая редакция может не использовать эти конечные точки и работать только со статическим ключом агента; +- детальная схема уровней и режимов доступа зафиксирована в `docs/agent-auth-model.md`. ### 5.8. Observability @@ -245,8 +263,9 @@ Нужны: -- list/create/revoke/delete platform API keys; -- one-time reveal значения ключа при создании. +- list/create/revoke/delete agent keys; +- one-time reveal значения ключа при создании; +- для расширенных редакций — выдача короткоживущих и одноразовых токенов. ### Secrets diff --git a/docs/agent-auth-model.md b/docs/agent-auth-model.md new file mode 100644 index 0000000..234340d --- /dev/null +++ b/docs/agent-auth-model.md @@ -0,0 +1,281 @@ +# Модель машинной аутентификации и уровней защиты операций + +## 1. Назначение документа + +Этот документ фиксирует целевую модель машинного доступа к опубликованным инструментам платформы. Модель строится вокруг двух принципов: + +- длинноживущий машинный доступ принадлежит конкретному AI-агенту, а не рабочей области в целом; +- требуемый уровень защиты определяется характером данных конкретной операции. + +Именно поэтому в системе должны быть одновременно: + +- ключ AI-агента как базовый машинный credential; +- режимы выдачи токенов разной строгости; +- обязательная политика защиты на уровне операции. + +## 2. Базовая идея + +Внутри платформы нужно различать: + +1. чем клиент подтверждает право подключиться к агенту; +2. какой уровень защиты требует операция; +3. достаточно ли текущего машинного доступа для вызова этой операции. + +Следовательно, решение нельзя строить только вокруг одного универсального токена. Оно должно учитывать и тип credential, и чувствительность самой ручки. + +## 3. Уровни защиты операции + +Каждая операция получает обязательный уровень защиты. + +### 3.1. `standard` + +Используется для обычных данных и типовых интеграционных вызовов. + +Разрешенный доступ: + +- статический ключ AI-агента; +- короткоживущий токен; +- одноразовый токен. + +### 3.2. `elevated` + +Используется для чувствительных внутренних данных, для которых постоянного ключа уже недостаточно. + +Разрешенный доступ: + +- короткоживущий токен; +- одноразовый токен. + +Статический ключ AI-агента для такого уровня уже недостаточен. + +### 3.3. `strict` + +Используется для максимально чувствительных данных, например содержащих коммерческую тайну, персональные данные высокой категории риска или иные критичные сведения. + +Разрешенный доступ: + +- только одноразовый токен на вызов. + +Ни статический ключ, ни обычный короткоживущий токен для такого вызова не должны считаться достаточными. + +## 4. Виды машинного доступа + +### 4.1. Статический ключ AI-агента + +Это длинноживущий ключ, принадлежащий одному агенту. + +Свойства: + +- привязан к одному `workspace`; +- привязан к одному `agent`; +- не используется для административных действий; +- может быть отозван и перевыпущен; +- в открытой редакции является основным механизмом подключения. + +### 4.2. Короткоживущий токен + +Это временный токен, выдаваемый на ограниченный срок. + +Свойства: + +- небольшой срок жизни; +- ограниченная область действия; +- может обновляться через стандартный поток OAuth 2.0; +- подходит для платформенного размещения, где важен баланс удобства и безопасности. + +### 4.3. Одноразовый токен + +Это токен, который разрешает один вызов конкретной операции или одной логической единицы доступа. + +Свойства: + +- очень короткий срок жизни; +- один допустимый вызов; +- после первого использования считается исчерпанным; +- предназначен для максимально чувствительных операций. + +## 5. Правило сопоставления + +Для вызова операции сервер сравнивает: + +- уровень машинного доступа клиента; +- обязательный уровень защиты операции. + +Правило простое: + +- если уровень доступа ниже, чем требует операция, вызов запрещается; +- если уровень доступа равен или выше, вызов разрешается. + +Именно это правило делает политику защиты независимой от того, в каком агенте опубликована операция. + +## 6. Роль AI-агента + +AI-агент: + +- группирует операции; +- формирует MCP-поверхность; +- имеет собственный ключ подключения. + +AI-агент не должен: + +- ослаблять уровень защиты операции; +- переопределять критичность данных; +- разрешать более слабый способ вызова, чем требует сама операция. + +Если в одном агенте опубликованы и обычные, и критичные операции, правила доступа к ним все равно различаются по уровню защиты самих операций. + +## 7. Поддержка по редакциям продукта + +### 7.1. Community + +Открытая редакция должна поддерживать только один режим: + +- статический ключ AI-агента. + +Соответственно, в Community допустимы только операции уровня: + +- `standard`. + +### 7.2. Cloud или управляемая платформа + +Для платформенного размещения должны поддерживаться: + +- статический ключ AI-агента как режим совместимости; +- короткоживущие токены по OAuth 2.0 как рекомендуемый режим. + +Соответственно, платформа может обслуживать операции уровня: + +- `standard`; +- `elevated`. + +### 7.3. Enterprise + +Для корпоративной редакции должны поддерживаться все три режима: + +- статический ключ AI-агента; +- короткоживущий токен; +- одноразовый токен. + +Соответственно, допускаются операции уровня: + +- `standard`; +- `elevated`; +- `strict`. + +## 8. Потоки аутентификации + +### 8.1. Community + +1. Пользователь создает AI-агента. +2. Платформа выдает статический ключ AI-агента. +3. Клиент `Codex`, `Claude Code` или другой MCP-клиент использует этот ключ как bearer token при подключении к MCP endpoint. + +Это самый простой и совместимый вариант. + +### 8.2. Cloud или управляемая платформа + +1. Пользователь или клиент проходит машинную аутентификацию. +2. Сервер авторизации выдает короткоживущий токен доступа. +3. Клиент использует его при работе с MCP endpoint. +4. По истечении срока действия токен обновляется через стандартный механизм обновления. + +Этот вариант должен опираться на OAuth 2.0 и обычный механизм refresh. + +### 8.3. Enterprise + +1. Клиент получает разрешение на вызов чувствительной операции. +2. Сервер выдает одноразовый токен. +3. Клиент выполняет один вызов. +4. Токен становится недействительным. + +Этот режим должен использоваться только там, где характер данных действительно требует такого уровня защиты. + +## 9. Опорные стандарты + +Для реализации расширенных режимов разумно опираться на готовые стандарты. + +### OAuth 2.0 + +Используется как основа для короткоживущих токенов и их обновления. + +### RFC 8693 + +Может использоваться как ориентир для схемы обмена одного вида machine credential на другой токен доступа. + +### RFC 9449 + +Может использоваться как ориентир для будущей привязки токена к ключевой паре клиента, если потребуется дополнительная защита от повторного использования перехваченного токена. + +## 10. Модель данных + +Для этой схемы достаточно следующих базовых сущностей. + +### `AgentKey` + +Поля: + +- `id` +- `workspace_id` +- `agent_id` +- `name` +- `prefix` +- `secret_hash` +- `status` +- `created_at` +- `last_used_at` +- `expires_at` + +### `IssuedAgentToken` + +Поля: + +- `id` +- `workspace_id` +- `agent_id` +- `token_kind` +- `status` +- `expires_at` +- `used_at` +- `max_uses` +- `used_count` +- `created_at` + +### Поля операции + +На уровне операции должна появиться обязательная политика: + +- `security_level` + +Допустимые значения: + +- `standard` +- `elevated` +- `strict` + +## 11. Административный интерфейс + +Настройка должна быть максимально простой. + +На этапе создания или редактирования операции пользователь выбирает: + +- `Обычный` +- `Повышенная защита` +- `Максимальная защита` + +Смысл вариантов: + +- `Обычный` — стандартный уровень для обычных данных; +- `Повышенная защита` — короткоживущий токен; +- `Максимальная защита` — одноразовый токен. + +Пользователь не должен вручную настраивать детали OAuth или внутреннюю механику выдачи токенов на уровне операции. + +## 12. Практический итог + +Целевая модель машинного доступа для Crank должна строиться так: + +- в Community — статический ключ AI-агента; +- в управляемой платформе — короткоживущие токены; +- в Enterprise — при необходимости одноразовые токены; +- уровень защиты определяется операцией, а не агентом; +- агент никогда не ослабляет обязательную защиту опубликованной операции. diff --git a/docs/alpine-ui-integration-plan.md b/docs/alpine-ui-integration-plan.md index 73bad74..c4e2857 100644 --- a/docs/alpine-ui-integration-plan.md +++ b/docs/alpine-ui-integration-plan.md @@ -1,5 +1,10 @@ # Alpine UI Integration Plan +Примечание: + +- разделы, где машинный доступ UI описан через `platform-api-keys`, требуют обновления на модель `agent keys -> short-lived tokens`; +- источником истины по этой части следует считать `docs/agent-auth-model.md`, `docs/admin-api.md` и `docs/mcp-interface.md`. + ## 1. Назначение документа Этот документ фиксирует, как Alpine UI в `apps/ui` подключается к реальному backend. diff --git a/docs/architecture.md b/docs/architecture.md index e24c41c..b5a4234 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -29,7 +29,7 @@ Crank - платформа для публикации внешних API в в - `Workspace` - tenant boundary; - `Operation` - интеграционный контракт; - `Agent` - curated MCP surface; -- `Platform API key` и `Membership` - доступ к самой платформе; +- `Agent key`, `Agent token` и `Membership` - доступ к самой платформе; - `Invocation log` и `Usage rollup` - observability слой. `Operation` остается фундаментом интеграции, но tools больше не публикуются глобально. MCP публикует tools в контексте конкретного `workspace` и конкретного `agent`. @@ -44,7 +44,8 @@ Crank - платформа для публикации внешних API в в - secrets; - auth profiles; - agents; -- platform API keys; +- agent keys; +- short-lived agent tokens; - logs и usage; - пользователей и роли. @@ -59,10 +60,17 @@ Crank - платформа для публикации внешних API в в - `input_schema` - `input_mapping` - `execution_config` +- `security_level` - `output_mapping` - `tool_description` - `status` +Принцип: + +- уровень защиты определяется самой операцией; +- агент не может ослабить обязательный режим доступа; +- для более чувствительных данных требуется более строгий вид машинного credential. + ### `Agent` Является пользовательской MCP-поверхностью для LLM. @@ -75,6 +83,8 @@ Crank - платформа для публикации внешних API в в - формирует отдельный MCP endpoint; - решает проблему "одному агенту нельзя отдавать 100 tools сразу". +При этом `Agent` не определяет чувствительность операции, а только публикует ее в составе MCP-поверхности. + ### `Platform access` Отдельный слой, не связанный с upstream auth: @@ -83,7 +93,16 @@ Crank - платформа для публикации внешних API в в - `UserSession` - `Membership` - `Invitation` -- `PlatformApiKey` +- `AgentKey` +- `IssuedAgentToken` + +Принцип: + +- пользовательская аутентификация и машинная аутентификация разделены; +- длинноживущий доступ для вызова MCP tools привязан к конкретному агенту, а не к рабочей области целиком; +- в открытой редакции базовый режим строится на статическом ключе агента; +- в более защищенных редакциях используются короткоживущие и одноразовые токены; +- промежуточная схема с workspace-scoped ключами рассматривается как переходная и подлежит замене. ### `Upstream secrets` @@ -133,7 +152,8 @@ Crank - платформа для публикации внешних API в в - Controlled streaming operations поверх `Streamable HTTP`, REST SSE, gRPC server-streaming и WebSocket upstream. - `Agent` и привязка операций к агенту. - Agent-scoped MCP endpoints. -- Platform API keys. +- Agent-scoped machine credentials. +- Short-lived MCP access tokens. - Workspace-scoped encrypted secrets для upstream access. - Workspace-scoped auth profiles для upstream access. - Product logs и usage aggregates. @@ -171,7 +191,7 @@ Crank - платформа для публикации внешних API в в ### Администратор workspace -1. Управляет API keys платформы. +1. Управляет ключами AI-агентов и доверенных клиентов платформы. 2. Управляет пользователями и ролями. 3. Смотрит logs и usage. @@ -266,7 +286,8 @@ GraphQL в MCP публикуется как фиксированная опер - `StreamSession` - `AsyncJobHandle` - `AuthProfile` -- `PlatformApiKey` +- `AgentKey` +- `IssuedAgentToken` - `UserSession` - `InvocationLog` - `UsageRollup` diff --git a/docs/as-is-to-be.md b/docs/as-is-to-be.md index c0f3c08..cb196db 100644 --- a/docs/as-is-to-be.md +++ b/docs/as-is-to-be.md @@ -1,5 +1,11 @@ # As Is -> To Be +Примечание: + +- разделы этого документа, где машинный доступ описан через workspace-scoped `platform API keys`, следует считать устаревшими; +- целевая модель проекта переведена на `AgentKey`, короткоживущие токены доступа и при необходимости `PlatformClientCredential`; +- подробности переноса зафиксированы в `docs/agent-auth-model.md`. + ## 1. Назначение документа Этот документ фиксирует переход от текущего состояния проекта к целевой продуктовой модели, отраженной в текущем Alpine UI. diff --git a/docs/backend-gap-plan.md b/docs/backend-gap-plan.md index d17513c..4d8397b 100644 --- a/docs/backend-gap-plan.md +++ b/docs/backend-gap-plan.md @@ -1,5 +1,10 @@ # Backend Gap Plan +Примечание: + +- пункты этого плана, относящиеся к `PlatformApiKey` как основной машинной модели доступа, рассматриваются как переходные; +- актуальная целевая схема машинной аутентификации описана в `docs/agent-auth-model.md`. + ## 1. Назначение документа Этот документ превращает целевой Alpine UI и `docs/as-is-to-be.md` в конкретный backend-план. diff --git a/docs/data-model.md b/docs/data-model.md index 9a1fe41..f9644c2 100644 --- a/docs/data-model.md +++ b/docs/data-model.md @@ -46,7 +46,7 @@ - `OperationVersion` - `AuthProfile` - `Agent` -- `PlatformApiKey` +- `AgentKey` - `InvocationLog` - `UsageRollup` @@ -81,6 +81,22 @@ в рамках одной общей модели runtime и MCP publishing. +### 2.9. Уровень защиты задается операцией + +Обязательная политика машинного доступа задается на уровне `Operation`, а не на уровне `Agent`. + +Допустимые значения: + +- `standard` +- `elevated` +- `strict` + +Принцип: + +- если операция требует более строгий режим доступа, агент не может его ослабить; +- один агент может публиковать операции с разной критичностью данных; +- `mcp-server` сравнивает тип представленного credential с требуемым `security_level`. + ## 3. Корневые сущности ### 3.1. `Workspace` @@ -119,6 +135,7 @@ - `input_mapping` - `output_mapping` - `execution_config` +- `security_level` - `tool_description` - `samples` - `generated_draft` @@ -224,27 +241,59 @@ - config ссылается на `secret_id` или пару `secret_id`, если auth-схема составная; - runtime применяет profile к запросу только в момент вызова upstream. -### 3.9. `PlatformApiKey` +### 3.9. `AgentKey` -Отдельная сущность для доступа к самой платформе. +Отдельная сущность для машинного доступа к инструментам одного конкретного AI-агента. Поля: - `id` - `workspace_id` +- `agent_id` - `name` - `prefix` - `scopes` - `status` - `created_at` - `last_used_at` +- `expires_at` Секрет: -- полный secret показывается только один раз при создании; -- в persistent storage сохраняется только `secret_hash`. +- полное значение ключа показывается только один раз при создании; +- в persistent storage сохраняется только `secret_hash`; +- ключ не должен использоваться как основной рабочий токен вызова в целевой защищенной модели; +- ключ используется для выпуска короткоживущего токена доступа. -### 3.10. `User` +### 3.10. `IssuedAgentToken` + +Учет выданных машинных токенов для вызова MCP-инструментов. + +Поля: + +- `id` +- `workspace_id` +- `agent_id` +- `agent_key_id` +- `platform_client_id` +- `token_kind` +- `status` +- `scopes` +- `max_uses` +- `used_count` +- `cnf_jkt` +- `expires_at` +- `created_at` +- `used_at` + +Принцип: + +- токен живет ограниченное время; +- токен может быть одноразовым; +- токен может быть привязан к ключевой паре клиента; +- токен выражает более узкие права, чем длинноживущий ключ агента. + +### 3.11. `User` Поля: diff --git a/docs/database-schema.md b/docs/database-schema.md index 1ace2af..740fc4b 100644 --- a/docs/database-schema.md +++ b/docs/database-schema.md @@ -27,7 +27,8 @@ ### 2.5. Секреты не хранятся в открытом виде - upstream secrets живут в отдельных таблицах и шифруются; -- platform API keys хранятся как hash. +- agent keys и credentials доверенных клиентов хранятся как hash; +- короткоживущие токены хранятся в форме, пригодной для отзыва и учета использования. ## 3. Основные таблицы @@ -48,7 +49,9 @@ - `agent_versions` - `agent_operation_bindings` - `published_agents` -- `platform_api_keys` +- `agent_keys` +- `issued_agent_tokens` +- `platform_client_credentials` - `stream_sessions` - `async_jobs` - `invocation_logs` @@ -65,6 +68,7 @@ - `display_name` - `protocol` - `status` +- `security_level` - `current_draft_version` - `latest_published_version` - `created_at` @@ -196,6 +200,59 @@ - `unique (workspace_id, name)` +### `agent_keys` + +- `id` +- `workspace_id` +- `agent_id` +- `name` +- `prefix` +- `secret_hash` +- `scopes_json` +- `status` +- `expires_at` +- `created_at` +- `last_used_at` + +Ограничения: + +- `unique (agent_id, name)` +- `prefix` уникален глобально + +Назначение: + +- длинноживущий ключ принадлежит одному агенту; +- ключ используется как исходное основание для выпуска короткоживущего токена; +- прямой вызов MCP по такому ключу допускается только в переходном режиме. + +### `issued_agent_tokens` + +- `id` +- `workspace_id` +- `agent_id` +- `agent_key_id` +- `token_kind` +- `status` +- `scopes_json` +- `max_uses` +- `used_count` +- `cnf_jkt` +- `expires_at` +- `created_at` +- `used_at` + +Индексы: + +- `(agent_id, status, expires_at)` +- `(workspace_id, status, expires_at)` +- `(cnf_jkt)` при включенной привязке токена к ключевой паре клиента + +Назначение: + +- учет выданных короткоживущих токенов; +- поддержка одноразовых токенов; +- поддержка отзыва и проверки повторного использования. + ### `stream_sessions` - `id` @@ -336,20 +393,38 @@ - `published_at` - `published_by` -## 9. Platform access and observability +## 9. Machine access and observability -### `platform_api_keys` +### `agent_keys` - `id` - `workspace_id` +- `agent_id` - `name` - `prefix` - `secret_hash` - `scopes_json` - `status` +- `expires_at` - `created_at` - `last_used_at` +### `issued_agent_tokens` + +- `id` +- `workspace_id` +- `agent_id` +- `agent_key_id` +- `token_kind` +- `status` +- `scopes_json` +- `max_uses` +- `used_count` +- `cnf_jkt` +- `expires_at` +- `created_at` +- `used_at` + ### `invocation_logs` - `id` @@ -397,6 +472,6 @@ 3. добавить `secrets` и `secret_versions`; 4. перевести `auth_profiles` на secret-backed config; 5. добавить `agents` и `published_agents`; -6. внедрить `platform_api_keys`; +6. внедрить `agent_keys`, `platform_client_credentials` и `issued_agent_tokens`; 7. добавить `invocation_logs` и `usage_rollups`; 8. перевести MCP runtime на `published_agents`, а не на глобальный список operations. diff --git a/docs/diagrams.md b/docs/diagrams.md index f74c114..9e80010 100644 --- a/docs/diagrams.md +++ b/docs/diagrams.md @@ -8,6 +8,12 @@ - связи между доменными сущностями; - хранение данных в БД. +Примечание: + +- диаграммы требуют следующего обновления по слою машинного доступа; +- вместо `PlatformApiKey` целевая модель проекта теперь использует `AgentKey`, `IssuedAgentToken` и при необходимости `PlatformClientCredential`; +- детальная схема зафиксирована в `docs/agent-auth-model.md`. + ## 2. Компонентная диаграмма ```mermaid diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md index 3837f97..be8999b 100644 --- a/docs/implementation-plan.md +++ b/docs/implementation-plan.md @@ -74,19 +74,35 @@ DoD: - binding operations к agent работает; - published agent появляется в MCP runtime. -## 7. Этап 6. Platform access +## 7. Этап 6. Agent-scoped machine access Цель: -- реализовать workspace access и platform API keys. +- реализовать machine access на уровне AI-агента и ввести обязательный уровень защиты операции. DoD: -- UI screens `API Keys`, `Settings`, `Workspace` имеют backend-контракт; -- platform API keys не смешиваются с upstream auth profiles; -- tenant boundary выражен в access layer. +- UI умеет выпускать и отзывать ключи конкретного AI-агента; +- длинноживущий машинный доступ больше не описывается ключом рабочей области; +- у операции появляется обязательный `security_level`; +- machine access не смешивается с upstream auth profiles; +- Community поддерживает базовый режим со статическим ключом AI-агента. -## 8. Этап 7. Observability +## 8. Этап 7. Token exchange and short-lived auth + +Цель: + +- внедрить расширенные режимы доступа для операций повышенной чувствительности. + +DoD: + +- существует конечная точка выдачи токена по ключу агента; +- есть модель одноразового токена для чувствительных вызовов; +- токены ограничены по сроку жизни, области действия и числу использований; +- операции уровня `elevated` нельзя вызвать по статическому ключу; +- операции уровня `strict` можно вызвать только по одноразовому токену. + +## 9. Этап 8. Observability Цель: @@ -98,7 +114,7 @@ DoD: - есть продуктовые endpoints, а не только application logs; - rollups и detail views согласованы с UI. -## 9. Этап 8. Alpine UI integration +## 10. Этап 9. Alpine UI integration Цель: @@ -110,7 +126,7 @@ DoD: - mock JSON больше не используется на критическом пути; - UI, backend и docs синхронизированы. -## 10. Этап 9. Secret store and upstream auth +## 11. Этап 10. Secret store and upstream auth Цель: @@ -124,7 +140,7 @@ DoD: - runtime умеет применять bearer/basic/api-key auth к реальному upstream request; - wizard имеет auth selector и quick-create flow для secrets/auth profiles. -## 11. Этап 10. Hardening and demo readiness +## 12. Этап 11. Hardening and demo readiness Цель: @@ -136,7 +152,7 @@ DoD: - deployment и healthchecks стабильно зелёные; - документация и продуктовый сценарий совпадают. -## 12. Этап 11. MCP streaming proxy support +## 13. Этап 12. MCP streaming proxy support Цель: @@ -150,7 +166,7 @@ DoD: - UI умеет конфигурировать streaming limits, aggregation и lifecycle; - e2e сценарии покрывают window/session/job calls. -## 13. Этап 12. WebSocket upstream support +## 14. Этап 13. WebSocket upstream support Цель: @@ -163,7 +179,7 @@ DoD: - heartbeat, reconnect и subscription lifecycle конфигурируются явно; - docs, UI и e2e синхронизированы. -## 14. Этап 13. SOAP support +## 15. Этап 14. SOAP support Цель: @@ -176,7 +192,7 @@ DoD: - operator может выбрать service, port и operation; - test-run, publish и observability работают так же, как для остальных протоколов. -## 15. Этап 14. Detailed streaming specs +## 16. Этап 15. Detailed streaming specs Цель: @@ -188,7 +204,7 @@ DoD: - protocol docs не противоречат общей execution model; - roadmap и `TASKS.md` синхронизированы с full-detail architecture. -## 16. Этап 15. Streaming implementation slices +## 17. Этап 16. Streaming implementation slices Цель: diff --git a/docs/mcp-interface.md b/docs/mcp-interface.md index f83e4d6..fdbeb93 100644 --- a/docs/mcp-interface.md +++ b/docs/mcp-interface.md @@ -98,16 +98,29 @@ ## 7.1. MCP authentication -`mcp-server` использует workspace-scoped `platform API keys` как machine credentials. +Целевая модель машинной аутентификации для `mcp-server` строится вокруг AI-агента, а не вокруг рабочей области целиком. При этом допустимый способ вызова определяется не только агентом, но и уровнем защиты самой операции. Контракт: -- клиент передает `Authorization: Bearer crk_...`; -- ключ должен принадлежать workspace из path; -- `read` разрешает `initialize`, `notifications/initialized`, `ping`, `tools/list`; -- `write` разрешает `tools/call`; -- `deploy` сейчас включает те же MCP права, что и `write`, и зарезервирован для deploy-scoped automation; -- успешная аутентификация обновляет `platform_api_keys.last_used_at`. +- каждому published agent соответствует собственный длинноживущий `agent key`; +- `agent key` принадлежит одновременно `workspace` и `agent`; +- в редакции `Community` вызовы допускаются по статическому `agent key`; +- в управляемой платформе для операций уровня `elevated` должен использоваться короткоживущий токен; +- в редакции `Enterprise` для операций уровня `strict` должен использоваться одноразовый токен; +- операция задает обязательный `security_level`, и `mcp-server` обязан отклонять вызов, если представленный credential слабее требуемого уровня; +- детальная модель уровней зафиксирована в `docs/agent-auth-model.md`. + +Уровни защиты операции: + +- `standard` +- `elevated` +- `strict` + +Правило применения: + +- `standard` допускает статический ключ агента, короткоживущий токен и одноразовый токен; +- `elevated` допускает короткоживущий токен и одноразовый токен; +- `strict` допускает только одноразовый токен. ## 8. MCP lifecycle diff --git a/docs/module-decomposition.md b/docs/module-decomposition.md index 2bf05cc..6cbecf5 100644 --- a/docs/module-decomposition.md +++ b/docs/module-decomposition.md @@ -102,9 +102,10 @@ - хранение workspace-scoped operations и version snapshots; - хранение workspace-scoped secrets и secret versions; - хранение agents и agent versions; +- хранение agent keys и выданных agent tokens; - хранение stream sessions и async jobs; - auth profiles; -- platform API keys; +- platform client credentials; - logs и usage aggregates; - metadata по sample artifacts и descriptors. @@ -138,7 +139,8 @@ - `operations` - `auth_profiles` - `agents` -- `platform_api_keys` +- `agent_keys` +- `platform_clients` - `logs` - `usage` - `streaming`