fix(selfhost): use ownership tokens for transient PR actuation locks - #3153
fix(selfhost): use ownership tokens for transient PR actuation locks#3153RealDiligent wants to merge 3 commits into
Conversation
Per-PR actuation and AI-review mutexes claimed Redis keys with a constant value and released via blind del(). A holder running past the TTL could delete a successor's live lock in finally, reopening merge/close races the mutex exists to prevent (JSONbored#2129/JSONbored#2135). Store a per-holder UUID at claim time and release with compare-and-delete (releaseIfValue) on the Redis cache adapter. Skip release when fail-open (no cache) or when the adapter lacks compare-and-delete (TTL backstop). Co-authored-by: Cursor <cursoragent@cursor.com>
Add regression tests for caches without releaseIfValue and for releaseIfValue failures so stale-holder protection branches are fully exercised. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3153 +/- ##
=======================================
Coverage 96.06% 96.06%
=======================================
Files 260 260
Lines 28684 28696 +12
Branches 10437 10440 +3
=======================================
+ Hits 27555 27567 +12
Misses 493 493
Partials 636 636
🚀 New features to boost your workflow:
|
|
Caution 🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥 🛑 Gittensory review result - reject/close recommendedReview updated: 2026-07-04 17:35:02 UTC
🛑 Suggested Action - Reject/Close
Review summary Blockers
Nits — 5 non-blocking
Why this is blocked
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
…behavior Co-authored-by: Cursor <cursoragent@cursor.com>
|
Gittensory is closing this pull request on the maintainer's behalf (AI reviewers agree on a likely critical defect: src/queue/processors.ts:3388 makes `releaseTransientLockIfOwner` skip release whenever a cache adapter has `claim` but no `releaseIfValue`, so any existing self-host adapter matching the still-legal `SELFHOST_TRANSIENT_CACHE` shape in `src/env.d.ts` will keep PR actuation locks for 600 seconds and AI-review locks for 1800 seconds after normal successful work; either make `releaseIfValue` required for adapters that expose `claim`, lower/partition the compatibility TTL behavior, or change the interface so startup/config rejects `claim` without ownership-aware release instead of silently blocking follow-up work. ```ts if (cache?.claim && !cache.releaseIfValue) { throw new Error("SELFHOST_TRANSIENT_CACHE.claim requires releaseIfValue for ownership-aware locks"); } ```). This is an automated maintenance action — to pursue this change, please open a new pull request with the issues resolved. Closed PRs may be analyzed later to improve review accuracy, but they are not automatically reopened or re-reviewed. |
Ownership-token release fixed stale-holder blind del() (JSONbored#2129), but skipping release when releaseIfValue was absent pinned locks for 600s/1800s after normal work on misconfigured adapters (JSONbored#3153). - Boot: assertSelfhostTransientCacheOwnershipRelease() in server.ts - Runtime: fail open without calling claim() when releaseIfValue is missing - Tests: stale-holder regressions for both lock namespaces, boot guard, JSONbored#3153 path Co-authored-by: Cursor <cursoragent@cursor.com>
…rs (#3164) Ownership-token release fixed stale-holder blind del() (#2129), but skipping release when releaseIfValue was absent pinned locks for 600s/1800s after normal work on misconfigured adapters (#3153). - Boot: assertSelfhostTransientCacheOwnershipRelease() in server.ts - Runtime: fail open without calling claim() when releaseIfValue is missing - Tests: stale-holder regressions for both lock namespaces, boot guard, #3153 path Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Fixes a production race in transient PR actuation locks where a stale holder's
finallyblock could blind-del()a successor's live lock after TTL expiry, reopening merge/close actuation races (#2129/#2135).Problem
claimTransientLock()stored a constant"1"as the lock value.releasePrActuationLock/releaseAiReviewLockused unconditionaldel(key). If holder A ran past the TTL, holder B claimed the lock, and A's stale cleanup ran afterward, A deleted B's lock — restoring the exact cross-worker race the mutex was meant to prevent.Root cause
Lock release was not ownership-aware. There was no compare-and-delete primitive on the transient cache adapter, and release always deleted by key regardless of who currently held the lock.
Implementation
releaseIfValue(key, value)to the Redis transient cache (Lua compare-and-delete).SELFHOST_TRANSIENT_CACHEwith optionalreleaseIfValue.claimTransientLock()now generates a UUID owner token and returns{ acquired, ownerToken }.releaseTransientLockIfOwner()releases only when the token matches; skips blinddel()whenreleaseIfValueis unavailable (TTL backstop).Testing performed
npm run typechecktest/unit/queue.test.ts(including stale-holder regression, no-releaseIfValueadapter, andreleaseIfValueerror path)test/unit/selfhost-redis-cache.test.ts(releaseIfValueLua path)test/unit/ai-review-advisory.test.tsfor new lock APIupstream/main(62059b0f)Compatibility
claimPrActuationLock,claimAiReviewLockreturnTransientLockClaiminstead ofboolean; release helpers takeownerToken: string | null. These are internal/selfhost exports used only within this repo's call sites (all updated).releaseIfValueretain prior fail-open claim behavior but no longer perform unsafe blind release — locks expire via TTL instead.Why this approach
Compare-and-delete is the minimal correct fix for Redis-style transient locks without introducing a heavier per-PR Durable Object. It directly addresses the documented KNOWN LIMITATION while preserving existing TTL crash-safety semantics.
Supersedes closed #2991 (same change, rebased + additional codecov branch coverage).
Scope
CONTRIBUTING.md.Validation
npm run typechecknpm run test:cipending CI (Windows-local full suite has environment-specific failures unrelated to this change)Safety
releaseIfValue, and release errors.Notes
Prior PR #2991 reached maintainer approval but was closed when
codecov/patchreported 96.15% on the changed hunk. This revision adds explicit tests for the intentionally skipped blind-del()path and the best-effort release error handler.