fix(keys): ephemeral key TTL 15m → 60m (long runs outlive the key, chat#1839)#751
Conversation
…hat#1839) The TTL is only the backstop: runAgentWorkflow revokes the key on run end via deleteEphemeralKeyStep, so this does not extend key life on normal completion. But a runAgentStep timeout retries the whole agent loop (~10+ min per attempt), and on 2026-07-03 a customer run's final sends all 401'd on the expired key after 3 step retries (email_send_log 'rejected' rows with null account_id). 60 minutes covers several retry cycles; the chat#1839 refresh mechanism remains the proper long-term fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 1 minute Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
No issues found across 2 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant Runner as runAgentWorkflow
participant KeyModule as mintEphemeralAccountKey
participant DB as Supabase (api_keys table)
participant Agent as runAgentStep (loop)
participant Email as POST /api/emails
Note over Runner,Email: Ephemeral Key Lifecycle (long-run scenario)
Runner->>KeyModule: mintEphemeralAccountKey()
KeyModule->>KeyModule: TTL = 60 * 60 * 1000 (60m)
KeyModule->>DB: insertApiKey(expires_at = now + 60m)
DB-->>KeyModule: keyId, rawKey
KeyModule-->>Runner: rawKey + keyId
loop Agent execution with retries
Runner->>Agent: runAgentStep()
alt Step timeout (10+ min)
Agent-->>Runner: timeout / retry
Runner->>Agent: runAgentStep() retry
else Step succeeds
Agent-->>Runner: step result
end
end
Runner->>Email: POST /api/emails (with ephemeral key)
Note over Runner,Email: Key valid for 60m — survives retries
Email->>DB: verify key validity (expires_at check)
DB-->>Email: valid
Email-->>Runner: 200 OK
opt Run completes normally
Runner->>Runner: deleteEphemeralKeyStep (finally block)
Runner->>DB: revoke key (cleanup)
Note over Runner,DB: Key revoked regardless of TTL
end
alt Key expired before run ends (was 15m TTL)
Note over Email: NEW: 60m TTL prevents this failure mode
Email->>DB: verify key validity
DB-->>Email: expired (401)
Email-->>Runner: 401 Unauthorized
Note over Runner,Email: History: 3 rejected rows in email_send_log, null account_id, zero deliveries
end
Requires human review: Extends key TTL from 15 to 60 minutes, a security-sensitive change affecting authentication lifetime. Requires human review to assess timing and revocation guarantees.
Re-trigger cubic
Preview verification — 2026-07-03 ~19:15 UTCTested against the PR's preview deployment 1. Minted TTL is 60 minutes ✅Fired
2. Prod control still mints 15 minutes ✅Production ( 3. TTL remains a backstop — revocation on run end still works ✅The preview run's 60-min key was deleted when its run ended (~3 minutes after mint; row gone from Also exercised end-to-end on the preview: a first trivial run (19:10:57, 🤖 Generated with Claude Code |
Why
Headless runs that outlive the 15-minute ephemeral key TTL lose auth mid-flight — typically at the final email send, the most expensive place to fail. On 2026-07-03 a customer-facing LA EQUIS report run hit a
runAgentSteptimeout, retried 3× (each retry restarts the whole agent loop, ~10+ min per attempt), and everyPOST /api/emailsattempt then 401'd on the expired key: threerejectedrows inemail_send_logwith nullaccount_id, zero deliveries. This is the exact failure signature documented in recoupable/chat#1839.What
DEFAULT_EPHEMERAL_KEY_TTL_MS: 15 min → 60 min, with a JSDoc explaining the reasoning.Why this is safe
The TTL is only the backstop:
runAgentWorkflowrevokes the key the moment the run ends (deleteEphemeralKeyStepin thefinallyblock), so this change does not extend key life on normal completion — it only stops killing legitimate long runs. The chat#1839 decision to prefer refresh-over-extend still stands as the proper long-term fix; that issue also names TTL scaling as the acceptable fallback, which this implements in its simplest form.Verification
pnpm test lib/keys/— 13/13 green.pnpm exec tsc --noEmit— the only errors are pre-existing onmaininlib/trigger/__tests__(untouched by this diff).Refs recoupable/chat#1839.
🤖 Generated with Claude Code
Summary by cubic
Increase ephemeral account key TTL from 15 to 60 minutes so long headless runs stay authenticated through retries. Aligns with
recoupable/chat#1839; TTL remains a backstop since keys are revoked when runs end.DEFAULT_EPHEMERAL_KEY_TTL_MSto 60m; expanded doc comment with retry rationale.Written for commit 324367b. Summary will update on new commits.