Ротируйте секрет
Замените секретный объект credential под оптимистичной блокировкой и докажите, что ротация прошла.
Вендорский ключ утёк, истёк или просто состарился по политике. Ротация здесь — это замена секрета целиком под оптимистичной блокировкой — без частичных слияний, без изменения статусов.
Цель
Закончить с той же записью credential (тот же id), несущей новый секрет: version инкрементирована, маска изменилась, конфигурация нетронута.
Предварительные условия
- Активный credential из сценария 02; его
idи текущаяversion.
Шаги
1. Прочитайте текущее состояние
Вызовите GET /v1/credentials/{id} и сохраните version и masked_credentials для сравнения.
2. Ротируйте
Вызовите PATCH /v1/credentials/{id} с полным новым секретным объектом и текущей версией:
curl -s -X PATCH "$CREDS_BASE/v1/credentials/$CRED_ID" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"credentials": {"api_key": "sk-live-fedcba9876543210"},
"version": 1
}'
r = httpx.patch(f"{CREDS_BASE}/v1/credentials/{cred_id}", headers=headers, json={
"credentials": {"api_key": "sk-live-fedcba9876543210"},
"version": current_version,
})
assert r.status_code == 200
rotated = r.json()
Ожидаемый 200: version увеличена, masked_credentials заметно другая (маска пересчитывается из нового plaintext), is_default и status нетронуты. Старый секрет исчез — перешифрованное хранилище держит только новый объект.
3. Докажите, что блокировка вас защищает
Повторите тот же PATCH со старой версией:
curl -s -X PATCH "$CREDS_BASE/v1/credentials/$CRED_ID" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"credentials": {"api_key": "sk-live-stale-write"}, "version": 1}'
Ожидаемый 409 с error.code = "CREDENTIAL_VERSION_CONFLICT" — конкурентный редактор не может молча перезаписать вашу ротацию. Перечитать, затем повторить — таков контракт.
Ротация организационного или платформенного ключа — тот же вызов
Идентичный PATCH существует на /v1/org-credentials и на внутренней админ-плоскости; отличаются только владение и гейт.
Проверено тестом test_s03_rotate_a_secret.