Skip to content

fix: make API key rotation atomic and replayable - #1624

Merged
kang-heewon merged 1 commit into
trunkfrom
fix/1585-atomic-api-key-rotation
Jul 29, 2026
Merged

fix: make API key rotation atomic and replayable#1624
kang-heewon merged 1 commit into
trunkfrom
fix/1585-atomic-api-key-rotation

Conversation

@kang-heewon

@kang-heewon kang-heewon commented Jul 29, 2026

Copy link
Copy Markdown
Member

Outcome

  • Replaces save-then-revoke rotation with one PostgreSQL transaction that locks the old key, persists the replacement and durable rotation intent, then conditionally revokes the old key.
  • Requires an idempotency key and returns the same protected replacement on retry instead of minting another active credential.
  • Persists stable post-commit event identity and claim state so failed publication can be recovered without repeating the rotation.
  • Protects replayable credentials with AES-256-GCM and authenticated rotation context; permanent key deletion purges linked recovery material transactionally.
  • Routes auth changes through the real PostgreSQL CI suite and publishes the updated API, Problem, documentation, and changeset contracts.

Fixes #1585

Verification

  • Fresh PostgreSQL 16.10 rotation suite — 8/8 passed with immediate foreign keys, same-operation concurrency, competing rotations, revoke rollback, event recovery, deletion cleanup, and mixed-writer rollout evidence.
  • pnpm --filter @croco/auth-core test — 160/160 passed.
  • pnpm --filter @croco/auth-drizzle test — 62/62 passed; 8 environment-gated PostgreSQL tests also passed separately.
  • pnpm check — 24/25 passed, 1 not applicable, 0 failed.
  • pnpm docs:build — 115/115 tasks passed.
  • pnpm public-api:check, pnpm problem-registry:check, pnpm release-docs:check, and changeset-required verification passed.
  • Pre-push workspace tests — 232/232 tasks passed.
  • Pre-push workspace typecheck — 231/231 tasks passed.

Review gates

  • Correctness and regression: PASS — failure, retry, concurrency, immediate-FK, deletion, and post-commit recovery paths are covered against the real adapter.
  • Security and API: PASS — no plaintext recovery material is persisted; AES-GCM AAD binds ciphertext to the exact rotation; typed adapter and configuration contracts are exported and generated surfaces are synchronized.
  • Maintainability and rollout: PASS — serialization is owned by the store transaction, event delivery uses explicit durable state, and the required two-phase rollout is documented.
  • Independent adversarial review: APPROVE — all concurrency, migration, CI-routing, retention, and rollout findings were resolved.

Deployment contract

Apply the rotation schema first, pause rotation traffic, drain every instance using the legacy save-then-revoke path, deploy the new writers, and only then resume rotation. Mixed legacy and atomic rotation writers are unsupported because a legacy writer cannot participate in the new store transaction.

Retain every rotation-protection key for as long as records encrypted with it must remain replayable.

Summary by CodeRabbit

  • 새 기능

    • API 키 회전이 원자적으로 처리되며, 멱등성 키를 사용한 안전한 재시도를 지원합니다.
    • AES-256-GCM 기반 보호 기능으로 회전 중 민감한 키 정보가 안전하게 보관됩니다.
    • 이벤트 전달 실패 후에도 회전 상태를 복구할 수 있습니다.
    • PostgreSQL 저장소에서 회전 상태와 이벤트 처리를 지원합니다.
    • 회전 충돌, 잘못된 멱등성 키 등 관련 오류 유형이 추가되었습니다.
  • 문서

    • API 키 회전 설정, 마이그레이션 및 배포 절차를 문서화했습니다.
    • 새 API, 타입, 오류 코드에 대한 참조 문서를 추가했습니다.
  • 테스트

    • 동시 재시도, 충돌, 롤백, 복구 및 PostgreSQL 환경 검증을 추가했습니다.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kang-heewon, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 671d5699-c8fc-4763-a6b6-3b4b4c25caf2

📥 Commits

Reviewing files that changed from the base of the PR and between fc41832 and 87043dd.

⛔ Files ignored due to path filters (2)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (45)
  • .changeset/atomic-api-key-rotation.md
  • .github/workflows/ci.yml
  • docs/problem-code-registry.json
  • packages/auth-core/README.md
  • packages/auth-core/src/index.ts
  • packages/auth-core/src/libs/apikey/ApiKeyManager.ts
  • packages/auth-core/src/libs/apikey/ApiKeyRotationProtector.ts
  • packages/auth-core/src/libs/apikey/ApiKeyStore.ts
  • packages/auth-core/src/libs/interfaces/ApiKey.ts
  • packages/auth-core/src/libs/problems/AuthProblems.ts
  • packages/auth-core/src/tests/AesGcmApiKeyRotationProtector.spec.ts
  • packages/auth-core/src/tests/ApiKeyManager.spec.ts
  • packages/auth-core/src/tests/ApiKeySecurity.spec.ts
  • packages/auth-drizzle/README.md
  • packages/auth-drizzle/package.json
  • packages/auth-drizzle/src/index.ts
  • packages/auth-drizzle/src/libs/DrizzleApiKeyStore.ts
  • packages/auth-drizzle/src/migrations/addApiKeyRotations.ts
  • packages/auth-drizzle/src/schema/index.ts
  • packages/auth-drizzle/src/tests/DrizzleApiKeyStore.postgres.spec.ts
  • packages/auth-drizzle/src/tests/DrizzleApiKeyStore.spec.ts
  • packages/auth-drizzle/src/tests/DrizzleProviderConformance.spec.ts
  • packages/docs/src/content/docs/api/auth-core/src/classes/AesGcmApiKeyRotationProtector.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/ApiKeyManager.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/ApiKeyRotationConflictProblem.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/ApiKeyRotationProtectionProblem.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/ApiKeyStore.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/InvalidApiKeyRotationIdempotencyKeyProblem.md
  • packages/docs/src/content/docs/api/auth-core/src/interfaces/ApiKeyRotationProtector.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/AesGcmApiKeyRotationProtectorOptions.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/ApiKeyRotation.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/ApiKeyRotationInput.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/ApiKeyRotationPhaseStatus.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/ApiKeyRotationProtectionContext.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/RotateApiKeyOptions.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/RotateApiKeyResult.md
  • packages/docs/src/content/docs/api/auth-core/src/variables/API_KEY_ROTATION_PROTECTOR_TOKEN.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/classes/DrizzleApiKeyStore.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/functions/addApiKeyRotations.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/functions/removeApiKeyRotations.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/type-aliases/ApiKeyRotationMigrationClient.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/variables/apiKeyRotations.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • public-api-surface.snapshot.json
  • scripts/tests/ci-workflow.spec.ts
📝 Walkthrough

Walkthrough

API 키 로테이션을 멱등적·원자적으로 처리하도록 auth-core와 auth-drizzle의 계약, 암호화 보호기, 저장소 트랜잭션, 이벤트 복구, PostgreSQL 테스트, CI 경로, 문서와 문제 코드가 확장되었습니다.

Changes

원자적 API 키 로테이션

Layer / File(s) Summary
회전 계약과 보호기
packages/auth-core/src/libs/interfaces/ApiKey.ts, packages/auth-core/src/libs/apikey/ApiKeyRotationProtector.ts, packages/auth-core/src/libs/apikey/ApiKeyStore.ts
회전 입력·상태·결과 타입과 저장소의 회전 및 이벤트 처리 메서드가 추가되었고, AES-256-GCM 기반 복구 보호기가 구현되었습니다.
Manager 회전 및 이벤트 복구
packages/auth-core/src/libs/apikey/ApiKeyManager.ts, packages/auth-core/src/tests/*
idempotencyKey 검증, 보호기 필수 구성, 원자적 회전 저장, 이벤트 claim/complete/release, 멱등 재시도와 실패 복구가 반영되었습니다.
Drizzle 원자적 저장소
packages/auth-drizzle/src/libs/DrizzleApiKeyStore.ts, packages/auth-drizzle/src/schema/index.ts, packages/auth-drizzle/src/migrations/addApiKeyRotations.ts
회전 테이블과 마이그레이션이 추가되었으며, 키 잠금·교체·폐기를 단일 트랜잭션으로 처리하고 이벤트 상태와 복구 자료를 저장합니다.
PostgreSQL 검증과 CI 연결
packages/auth-drizzle/src/tests/DrizzleApiKeyStore.postgres.spec.ts, .github/workflows/ci.yml, scripts/tests/ci-workflow.spec.ts
동시 회전, 충돌, 롤백, 이벤트 복구, 삭제 정리 및 레거시 상태를 PostgreSQL에서 검증하고 관련 변경을 실제 리소스 테스트로 라우팅합니다.
문서와 공개 표면 갱신
packages/auth-core/README.md, packages/auth-drizzle/README.md, packages/docs/content/..., docs/problem-code-registry.json, public-api-surface.snapshot.json
새 API, 배포 절차, 회전 문제 코드와 공개 export가 문서 및 API 스냅샷에 반영되었습니다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant ApiKeyManager
  participant DrizzleApiKeyStore
  participant EventBus

  Caller->>ApiKeyManager: rotate(id, idempotencyKey)
  ApiKeyManager->>DrizzleApiKeyStore: atomic rotate with recovery ciphertext
  DrizzleApiKeyStore-->>ApiKeyManager: rotation result
  ApiKeyManager->>DrizzleApiKeyStore: claimRotationEvent
  ApiKeyManager->>EventBus: publish rotation event
  ApiKeyManager->>DrizzleApiKeyStore: completeRotationEvent
  DrizzleApiKeyStore-->>Caller: recovered rotation result
Loading

Possibly related PRs

  • croco-dev/framework#1411: auth-core와 auth-drizzle 변경을 PostgreSQL 실제 리소스 검증으로 라우팅하는 CI 변경이 연결됩니다.
  • croco-dev/framework#1611: 동일한 CI 경로 필터와 PostgreSQL 검증 실행 구성을 수정합니다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 API 키 회전을 원자적이고 재시도 가능한 방식으로 바꾸는 핵심 변경을 정확히 요약합니다.
Linked Issues check ✅ Passed 원자적 rotate, idempotency, 실제 PostgreSQL 저장소 테스트, 그리고 post-commit 복구 가능한 이벤트 처리 요구를 충족합니다.
Out of Scope Changes check ✅ Passed 변경 사항은 코드, 테스트, 문서, CI, 계약 갱신 등 PR 목표 범위 안에 있으며 불필요한 별도 기능 추가는 보이지 않습니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1585-atomic-api-key-rotation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown

📊 Benchmark Results

✅ All benchmarks passed

Benchmark p75 Threshold Baseline vs Baseline Status Notes
CrocoApp constructor 9.1μs 30.0ms 8.2μs +11.3% -
CrocoApp lambdaHandler (10 controllers) 257.9μs 50.0ms 258.4μs -0.2% -
Lambda cold-start simulation 532.9μs 80.0ms 418.1μs +27.5% -
Lambda cold-start with headers 394.8μs 80.0ms 369.7μs +6.8% -
Lambda cold-start with binary body 378.3μs 80.0ms 339.1μs +11.6% -
Lambda cold-start with query params 327.9μs 80.0ms 301.3μs +8.8% -
Lambda cold-start with authorizer context 323.1μs 80.0ms 299.8μs +7.8% -
Lambda cold-start realistic scenario 327.9μs 80.0ms 299.2μs +9.6% -
EventBusConfig.start (10 handlers) 1.6μs 10.0ms 1.4μs +14.7% -
EventPublisher.publishNow single event 1.9μs 2.0ms 1.7μs +10.7% -
DefaultHandlerResolver.resolve × 10 0.1μs 5.0ms 0.1μs -11.2% -
Container.get singleton (cold) 105.3μs 5.0ms 70.3μs +49.9% -
Container.register × 50 components 3.6ms 10.0ms 3.2ms +11.2% -
Container.validate (50 components) 4.1ms 20.0ms 3.4ms +19.7% -
Container.get singleton (warm) 1.7μs 500.0μs 1.6μs +5.0% -
TelemetryRuntime.init (lambda preset) 2.3μs 200.0ms 1.1ms -99.8% -
lambdaPreset config creation 1.5μs 2.0ms 1.4μs +4.3% -

Updated: 2026-07-29T20:52:06.104Z · Commit: 620894e

@kang-heewon
kang-heewon force-pushed the fix/1585-atomic-api-key-rotation branch from abc838c to fc41832 Compare July 29, 2026 19:23
coderabbitai[bot]
coderabbitai Bot previously requested changes Jul 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/auth-core/src/libs/apikey/ApiKeyManager.ts`:
- Around line 203-228: Update the rotation flow around ApiKeyManager’s
store.rotate call to persist eventStatus as "pending" for every rotation,
regardless of eventBus availability. Ensure the no-publisher path produces a
diagnostic degraded signal rather than returning degraded as false, while
preserving normal publishRotationEvent behavior when an eventBus is configured.
- Around line 171-182: Update ApiKeyManager.rotate to normalize
options.idempotencyKey once with trimming, validate that normalized value, and
use it consistently for protectionContext and store.rotate. Move the
rotationProtector configuration check before store.findById so missing
configuration fails without an unnecessary lookup.

In `@packages/auth-core/src/tests/AesGcmApiKeyRotationProtector.spec.ts`:
- Around line 14-54: AesGcmApiKeyRotationProtector tests lack coverage for
fail-closed key and ciphertext validation. Extend the suite around
constructor/requireKey and decrypt to assert ApiKeyRotationProtectionProblem for
a non-32-byte key, a malformed ciphertext such as “v1.a.b.c”, and decryption
with a protector whose keyId is no longer registered.

In `@packages/auth-core/src/tests/ApiKeyManager.spec.ts`:
- Around line 616-620: Map size assertions use toHaveLength incorrectly. In
packages/auth-core/src/tests/ApiKeyManager.spec.ts lines 616-620 and 657-660,
update the _getKeys() assertions in the idempotent retry and second logical
rotation rejection tests to assert _getKeys().size equals 2 with toBe(2).

In `@packages/auth-drizzle/src/libs/DrizzleApiKeyStore.ts`:
- Around line 337-399: Make the claim transition and replacement-key lookup
atomic in the rotation-event methods shown before completeRotationEvent and in
completeRotationEvent: wrap each update and subsequent findKeyWithClient lookup
in this.db.transaction, and roll back when the replacement cannot be found so a
failed lookup does not leave processing or completed state persisted. Preserve
the existing return mapping and claim/status conditions, or replace both steps
with a single joined query that provides the same atomic behavior.
- Around line 468-481: Update the transaction in the API key deletion flow to
inspect related rows in schema.apiKeyRotations before deleting them. If any
rotation has eventStatus pending or processing, reject the deletion with the
established Problem mechanism, or otherwise record observable evidence before
destruction; do not silently delete incomplete rotation events. Preserve
deletion of completed rotations and the apiKeys row.
- Around line 262-312: Update the rotation transaction around the replacement
insert and insertedIntent conflict handling so a conflicting intent cannot
commit the newly inserted active replacement key. Either detect and return the
existing rotation before inserting the replacement, with the required deferred
foreign-key behavior for newKeyId, or delete input.replacement.id in the
conflicting return path before returning; preserve normal rotation behavior and
ensure the old key is still revoked when appropriate.
- Around line 402-424: Update releaseRotationEvent to inspect the affected-row
result from the guarded update, using returning() or the database’s row-count
mechanism. Distinguish a successful release from a claim mismatch or
already-reclaimed event, and propagate that failure through the method’s
established diagnostic or boolean contract instead of silently resolving as
success; adjust the Promise return type and callers as needed.

In `@packages/auth-drizzle/src/migrations/addApiKeyRotations.ts`:
- Around line 9-24: Update the api_key_rotations table definition in
addApiKeyRotations to explicitly name the new_key_id uniqueness constraint
api_key_rotations_new_key_unique, matching the declaration in the schema index.
Keep the uniqueness behavior unchanged and avoid relying on PostgreSQL’s
generated constraint name.

In `@packages/auth-drizzle/src/tests/DrizzleApiKeyStore.postgres.spec.ts`:
- Around line 195-248: Move the database state assertion out of the
eventBus.publish callback in the test “recovers post-commit event publication
with the same event and credential.” Have the callback only collect the observed
state alongside the event, then assert the expected old-key revoked and new-key
active state after both rotate calls, outside the manager’s degraded
error-handling path.

In
`@packages/docs/src/content/docs/api/auth-drizzle/src/classes/DrizzleApiKeyStore.md`:
- Around line 30-33: Update the DrizzleApiKeyStore API documentation for
apiKeyRotations so it is documented as required rather than optional. Explain
that the table must be created and supplied, while noting that the constructor
falls back to defaultApiKeyRotations when it is not provided; keep the existing
PgTableWithColumns type unchanged.

In `@scripts/tests/ci-workflow.spec.ts`:
- Around line 241-248: Update the “routes auth changes to the real PostgreSQL
rotation suite” test to also assert that REAL_RESOURCE_JOB injects the
AUTH_POSTGRES_URL environment variable. Keep the existing workflow path and
command assertions unchanged, and verify the env key is present alongside the
PostgreSQL test command.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: cdb5c6ca-7bb4-4105-9352-c728004b460e

📥 Commits

Reviewing files that changed from the base of the PR and between 4f125b6 and fc41832.

⛔ Files ignored due to path filters (2)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (45)
  • .changeset/atomic-api-key-rotation.md
  • .github/workflows/ci.yml
  • docs/problem-code-registry.json
  • packages/auth-core/README.md
  • packages/auth-core/src/index.ts
  • packages/auth-core/src/libs/apikey/ApiKeyManager.ts
  • packages/auth-core/src/libs/apikey/ApiKeyRotationProtector.ts
  • packages/auth-core/src/libs/apikey/ApiKeyStore.ts
  • packages/auth-core/src/libs/interfaces/ApiKey.ts
  • packages/auth-core/src/libs/problems/AuthProblems.ts
  • packages/auth-core/src/tests/AesGcmApiKeyRotationProtector.spec.ts
  • packages/auth-core/src/tests/ApiKeyManager.spec.ts
  • packages/auth-core/src/tests/ApiKeySecurity.spec.ts
  • packages/auth-drizzle/README.md
  • packages/auth-drizzle/package.json
  • packages/auth-drizzle/src/index.ts
  • packages/auth-drizzle/src/libs/DrizzleApiKeyStore.ts
  • packages/auth-drizzle/src/migrations/addApiKeyRotations.ts
  • packages/auth-drizzle/src/schema/index.ts
  • packages/auth-drizzle/src/tests/DrizzleApiKeyStore.postgres.spec.ts
  • packages/auth-drizzle/src/tests/DrizzleApiKeyStore.spec.ts
  • packages/auth-drizzle/src/tests/DrizzleProviderConformance.spec.ts
  • packages/docs/src/content/docs/api/auth-core/src/classes/AesGcmApiKeyRotationProtector.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/ApiKeyManager.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/ApiKeyRotationConflictProblem.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/ApiKeyRotationProtectionProblem.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/ApiKeyStore.md
  • packages/docs/src/content/docs/api/auth-core/src/classes/InvalidApiKeyRotationIdempotencyKeyProblem.md
  • packages/docs/src/content/docs/api/auth-core/src/interfaces/ApiKeyRotationProtector.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/AesGcmApiKeyRotationProtectorOptions.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/ApiKeyRotation.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/ApiKeyRotationInput.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/ApiKeyRotationPhaseStatus.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/ApiKeyRotationProtectionContext.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/RotateApiKeyOptions.md
  • packages/docs/src/content/docs/api/auth-core/src/type-aliases/RotateApiKeyResult.md
  • packages/docs/src/content/docs/api/auth-core/src/variables/API_KEY_ROTATION_PROTECTOR_TOKEN.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/classes/DrizzleApiKeyStore.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/functions/addApiKeyRotations.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/functions/removeApiKeyRotations.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/type-aliases/ApiKeyRotationMigrationClient.md
  • packages/docs/src/content/docs/api/auth-drizzle/src/variables/apiKeyRotations.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • public-api-surface.snapshot.json
  • scripts/tests/ci-workflow.spec.ts

Comment thread packages/auth-core/src/libs/apikey/ApiKeyManager.ts
Comment thread packages/auth-core/src/libs/apikey/ApiKeyManager.ts
Comment thread packages/auth-core/src/tests/AesGcmApiKeyRotationProtector.spec.ts
Comment thread packages/auth-core/src/tests/ApiKeyManager.spec.ts
Comment thread packages/auth-drizzle/src/libs/DrizzleApiKeyStore.ts
Comment thread packages/auth-drizzle/src/libs/DrizzleApiKeyStore.ts
Comment thread packages/auth-drizzle/src/migrations/addApiKeyRotations.ts
Comment thread packages/auth-drizzle/src/tests/DrizzleApiKeyStore.postgres.spec.ts
Comment thread scripts/tests/ci-workflow.spec.ts
@kang-heewon
kang-heewon force-pushed the fix/1585-atomic-api-key-rotation branch from fc41832 to 62aea59 Compare July 29, 2026 20:12
@kang-heewon
kang-heewon dismissed coderabbitai[bot]’s stale review July 29, 2026 20:35

Superseded by commit 62aea59. Valid findings were fixed and verified; remaining comments were reviewed against the published contracts, answered with rationale, and resolved. The latest CodeRabbit status check passes.

@kang-heewon
kang-heewon force-pushed the fix/1585-atomic-api-key-rotation branch from 62aea59 to 87043dd Compare July 29, 2026 20:42
@kang-heewon
kang-heewon merged commit d7b2bde into trunk Jul 29, 2026
12 checks passed
@kang-heewon
kang-heewon deleted the fix/1585-atomic-api-key-rotation branch July 29, 2026 21:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[auth-core] API key rotation can leave both old and new credentials active

1 participant