fix(selfhost): fail open on a Redis write failure in the installation-token cache - #7035
Conversation
…-token cache set() had no try/catch around its redis.set call, unlike get()'s explicit fail-open contract. The token is already successfully minted from GitHub before set() is called, and the caller (createInstallationToken) has no try/catch of its own, so a transient Redis write failure was turning an otherwise-successful mint into a hard failure instead of just costing one extra real mint next time.
|
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 #7035 +/- ##
=======================================
Coverage 93.74% 93.74%
=======================================
Files 692 692
Lines 68721 68723 +2
Branches 18760 18760
=======================================
+ Hits 64424 64426 +2
Misses 3302 3302
Partials 995 995
Flags with carried forward coverage won't be shown. Click here to find out more.
|
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-17 19:13:14 UTC
Review summary Nits — 5 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. 🟩 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 LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
Summary
src/selfhost/redis-token-cache.ts'sget()wraps itsredis.getcall in try/catch with an explicit fail-open contract (the caller,github/app.ts'screateInstallationToken, has no try/catch of its own, so an uncaught error would hard-fail GitHub App token minting on every Redis hiccup).set()— the sibling write call — had no try/catch at all.writeCachedToken(src/github/app.ts) callsexternalTokenStore.set(...)directly with no guard, right aftercreateInstallationTokensuccessfully obtains a fresh token from GitHub. A transient Redis write failure at that point threw uncaught and turned an otherwise-successful mint into a hard failure.set()'sredis.set(...)call in try/catch, matchingget()'s exact fail-open contract: on error, record a metric via the existingrecordTokenCacheMetric("error")and return without rethrowing. No change toget()or the TTL-flooring logic.Scope
type(scope): short summaryConventional Commit format.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #6999
Validation
git diff --checknpm run actionlintnpm run typecheck— the whole-repotsc --noEmitreliably OOMs on this shared, memory-constrained sandbox regardless of what changed; relied onnpm run build --workspace @loopover/engine(passed) plus the full targeted vitest run below as the local proxy, and CI's isolated runner for the authoritativetsc --noEmit.npm run test:coverage— full targeted run of both affected test files:test/unit/selfhost-redis-token-cache.test.ts(7 tests, incl. the newset()fail-open regression) andtest/unit/github-app.test.ts(93 tests, incl. a new end-to-end regression through the realcreateRedisTokenCache+createInstallationToken) — 100/100 passing.npm run test:workers/npm run build:mcp/npm run test:mcp-pack(not applicable — no Worker binding/queue or MCP packaging changes)npm run ui:openapi:check(no API/schema changes)npm run ui:lint— 0 errors (ran as a sanity check; this PR touches noapps/loopover-ui/**files)npm audit --audit-level=moderate(no dependency changes)If any required check was skipped, explain why:
npm run typecheckOOMs on this specific sandbox under current memory pressure, so it was not run standalone;npm run build --workspace @loopover/engineplus the full targeted test run above stand in as the local proxy, and CI's isolated runner performs the realtsc --noEmit.npm run test:workersand the MCP packaging checks have no surface to exercise for a change scoped to one try/catch in one self-host module.Safety
"sensitive-value") never reaches the Prometheus metrics text.createInstallationTokensuccess-despite-cache-failure path are tested.UI Evidencesection below with JPG/JPEG or PNG screenshots. (N/A — backend-only change, no UI surface.)Notes
no space left on deviceduring the Docker image export step on the CI runner.codecov/patch,codecov/project, and all 6validate-testsshards passed cleanly on that same run. Re-opening with the identical, unmodified code.