# Secrets And Upstream Auth Plan

## 1. Назначение документа

Этот документ фиксирует полный план доведения upstream secrets и `AuthProfile` до рабочей продуктовой модели.

Сейчас UI показывает оператору конструкцию вида `${secrets.API_KEY}`, но backend/runtime не резолвит ее в реальный secret. Это создает ложный контракт. Цель этого документа - заменить placeholder UX на рабочую систему.

## 2. Текущее состояние

Что уже есть:

- `AuthProfile` как отдельная workspace-scoped сущность;
- `auth_profile_ref` в `ExecutionConfig`;
- CRUD endpoints для `auth_profiles`;
- UI поля для upstream auth headers;
- env `CRANK_MASTER_KEY` в runtime docs.

Что еще не работает end-to-end:

- `secret_ref` не подтягивает фактическое значение секрета;
- wizard хранит auth как raw JSON headers;
- `${secrets.*}` в UI является только текстовым placeholder;
- отдельной страницы `Secrets` нет.

Что уже работает end-to-end:

- runtime резолвит `auth_profile_ref` при выполнении operation;
- `admin-api` test-runs используют тот же auth-aware execution path, что и `mcp-server`;
- `REST`, `GraphQL`, `gRPC`, `SOAP` и streaming execution paths получают bearer/basic/api-key auth до adapter layer;
- `last_used_at` у secret обновляется при успешном auth resolution.

## 3. Целевая модель

### 3.1. `Secret`

Metadata-сущность для upstream credentials.

Поля:

- `id`
- `workspace_id`
- `name`
- `kind`
- `status`
- `current_version`
- `created_at`
- `updated_at`

Типы:

- `token`
- `username_password`
- `header`
- `generic`

### 3.2. `SecretVersion`

Значение секрета, зашифрованное мастер-ключом.

Поля:

- `secret_id`
- `version`
- `ciphertext`
- `key_version`
- `created_at`

### 3.3. `AuthProfile`

`AuthProfile` больше не хранит plaintext или `${secrets.*}`.

Вместо этого profile описывает:

- тип auth (`bearer`, `basic`, `api_key_header`, `api_key_query`);
- как secret применяется к запросу;
- какие `secret_id` для этого нужны.

Примеры:

- bearer -> `secret_id`
- basic -> `username_secret_id` + `password_secret_id`
- api key header -> `header_name` + `secret_id`
- api key query -> `param_name` + `secret_id`

## 4. Хранение и шифрование

### 4.1. Где хранить

Стартовый вариант:

- metadata в `PostgreSQL`
- ciphertext в `PostgreSQL`

Это проще, чем отдельный Vault, и достаточно для текущего продукта.

### 4.2. Чем шифровать

- `AES-256-GCM`
- мастер-ключ в `CRANK_MASTER_KEY`
- поддержка `key_version` для будущей ротации

### 4.3. Что нельзя делать

- не хранить plaintext в БД;
- не возвращать plaintext в list/get endpoints;
- не писать plaintext в logs;
- не включать plaintext в YAML export/import.

## 5. Backend API

### 5.1. Secrets endpoints

- `GET /api/admin/workspaces/{workspace_id}/secrets`
- `POST /api/admin/workspaces/{workspace_id}/secrets`
- `GET /api/admin/workspaces/{workspace_id}/secrets/{secret_id}`
- `POST /api/admin/workspaces/{workspace_id}/secrets/{secret_id}/rotate`
- `DELETE /api/admin/workspaces/{workspace_id}/secrets/{secret_id}`

### 5.2. Auth profiles

Нужно доработать:

- `POST /auth-profiles`
- `PATCH /auth-profiles/{auth_profile_id}`

Чтобы `config_json` ссылался на `secret_id`, а не на строковые placeholders.

### 5.3. Validation rules

- нельзя удалить secret, если на него ссылается auth profile;
- нельзя удалить auth profile, если на него ссылается опубликованная operation, без явного подтверждения migration path;
- rotate не должен ломать существующие published operations.

## 6. Runtime changes

Перед upstream-вызовом runtime должен:

1. проверить `auth_profile_ref`;
2. загрузить `AuthProfile`;
3. загрузить и расшифровать нужный secret;
4. применить auth к request:
   - bearer -> `Authorization: Bearer ...`
   - basic -> `Authorization: Basic ...`
   - api key header -> произвольный header
   - api key query -> query param

Это изменение должно жить в runtime/orchestration слое, а не в UI.

## 7. UI placement

### 7.1. Отдельная страница `Secrets`

Нужна как основное место управления:

- list
- create
- rotate
- disable/delete
- usage references

Эта страница должна появиться рядом с `API Keys`.

### 7.2. Quick create в wizard

На шаге upstream вместо raw `Auth headers` нужен selector:

- `No auth`
- `Bearer token`
- `API key header`
- `Basic auth`

Дальше:

- `Select existing auth profile`
- `Create auth profile`
- `Create secret`

Это позволяет не вырывать оператора из flow создания operation.

### 7.3. Что убрать

Нужно убрать из UX:

- `${secrets.API_KEY}` как рекомендованный путь;
- raw JSON headers как основной способ настройки auth.

Raw headers можно оставить только как advanced override, но не как primary flow.

## 8. Вертикальные срезы реализации

### Срез 1. Secret store foundation

DoD:

- таблицы `secrets` и `secret_versions`;
- encryption/decryption service;
- CRUD/rotate endpoints;
- integration tests на create/get/rotate/delete.

### Срез 2. Auth profile refactor

DoD:

- auth profile config ссылается на `secret_id`;
- миграция со старой модели `secret_ref`/placeholder;
- validation на dangling references.

### Срез 3. Runtime auth resolution

DoD:

- `auth_profile_ref` применяется при `REST`, `GraphQL` и `gRPC` вызовах;
- test-run использует тот же кодовый путь;
- runtime tests покрывают bearer/basic/api-key-header/api-key-query.

### Срез 4. Secrets UI

DoD:

- новая страница `Secrets`;
- list/create/rotate/delete;
- read-only usage references через `AuthProfile`;
- no plaintext leaks after creation.

### Срез 5. Wizard auth UX

DoD:

- step 2 получает auth selector;
- quick-create secret/profile flow;
- public upstreams можно оставлять без auth;
- placeholder `${secrets.*}` исчезает из primary UX.

## 9. Риски

- без аккуратной миграции можно сломать уже созданные auth profiles;
- если шифрование сделать без `key_version`, потом будет болезненная ротация;
- если secrets page сделать без quick-create в wizard, UX снова станет медленным;
- если quick-create сделать без отдельной страницы, управляемость secrets будет плохой.

## 10. Практический итог

Следующий правильный roadmap:

1. `feat/secret-store-foundation`
2. `feat/auth-profile-secret-resolution`
3. `feat/secrets-ui`
4. `feat/wizard-auth-selector`
5. `feat/manual-regression-pass`

Сейчас `feat/wizard-auth-selector` уже закрыт: wizard использует auth selector на шаге 2, сериализует `auth_profile_ref` в `execution_config`, умеет quick-create для `Secret` и `AuthProfile`, а raw `Auth headers` убраны из primary UX. Следующий шаг - ручной regression pass по REST / GraphQL / gRPC / WebSocket / SOAP и проверка связки `Secrets -> Auth Profiles -> Test Run / MCP call`.
