Резолвите credentials
Пройдите цепочку USER → ORGANIZATION → PLATFORM с места рантайма и наблюдайте, как каждый уровень побеждает по очереди.
Взгляд с сервисной плоскости: рантайм перевода запрашивает эффективный ключ, и цепочка отвечает. Этот сценарий заготавливает все три уровня и промах, так что каждая ветка прохода показывает себя.
Цель
Наблюдать, как credential_source меняется с user на organization и на platform по мере исчезновения верхних уровней, и закончить промахом 404 CREDENTIAL_NOT_CONFIGURED.
Предварительные условия
- Сервисный токен со scope
provider-credentials.invoke:export SERVICE_TOKEN=...(Service Plane Tokens). - Заготовленные записи для одного провайдера: личный default пользователя, default организации, платформенный default (сценарии 02, 05, 07).
Шаги
1. Собственный ключ пользователя побеждает
Вызовите POST /internal/v1/credentials/resolve:
curl -s -X POST "$CREDS_BASE/internal/v1/credentials/resolve" \
-H "Authorization: Bearer $SERVICE_TOKEN" -H "Content-Type: application/json" \
-d '{
"user_id": "'$USER_ID'",
"org_id": "'$ORG_ID'",
"provider_code": "'$CODE'",
"purpose": "translation",
"correlation_id": "cookbook-06-a"
}'
Ожидаемый 200: credential_source: "user" и — уникально для этой плоскости — plaintext credentials. Обращайтесь соответственно (Resolve Chain).
2. Уберите пользовательский уровень — вступает организация
Удалите (или отключите) credential пользователя, снова резолвните с тем же телом. Ожидаемый 200 с credential_source: "organization", owner_id = UUID организации.
3. Уберите организацию из запроса — ловит платформа
Резолвните без org_id. Ожидаемый 200 с credential_source: "platform" — отсутствие контекста организации означает, что уровень пропускается целиком, и отдаёт общий fallback.
4. Запретите fallback — управляемый промах
Тот же запрос плюс "allow_platform_fallback": false:
r = httpx.post(f"{CREDS_BASE}/internal/v1/credentials/resolve",
headers={"Authorization": f"Bearer {SERVICE_TOKEN}"},
json={**body, "allow_platform_fallback": False})
assert r.status_code == 404
assert r.json()["error"]["code"] == "CREDENTIAL_NOT_CONFIGURED"
Ожидаемый 404 CREDENTIAL_NOT_CONFIGURED — провайдер существует, ничего допустимого не настроено. Каждый шаг этого сценария, попадания и промах равно, теперь виден в audit-ленте под вашими correlation id (сценарий 09).
Токенам с неверным scope отказывают, а не понижают их
Повторите шаг 1 с admin-scoped токеном: ожидаемый 403 FORBIDDEN. Resolve принадлежит одному лишь provider-credentials.invoke.
Проверено тестом test_s06_resolve_credentials.