Repository navigation
Keep tests off the operator's credential store and the network - #179
Merged
Merged
Conversation
[Medium impact] The PR appears safe to merge; no new actionable issues were found. SummaryThe PR keeps tests away from stored operator credentials and remote hosts.
Both earlier, unnumbered findings are addressed in the current code. Cache scopes stay registered through cleanup, and redirects are checked one hop at a time. No new actionable issues were found. Verification here was by code inspection; no tests were run. Reviews (2) · Last reviewed commit: "Close the test isolation gaps CI and rev..." · Reviewed by Greptile |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Three CursorPlugin shell hook tests called plugin.config with an empty temp cache and the native data root, so each read the developer's auth.json and ran live model discovery. A 2.x setup test sent its placeholder token to Cursor and the pollForTokens abort test polled it. test/preload.ts now points XDG_DATA_HOME into the run's TMPDIR, clears OPENCODE_AUTH_CONTENT and refuses every fetch and socket that leaves the machine; the test that tried one, or left the store redirected, fails. A timed-out test's body keeps running under Bun, so withTempHostCache restored the process-wide cache root late and the scope entered meanwhile restored a removed dir as the root for the rest of the file. The roots now go back when the test ends.
Without a Cursor CLI install, as in CI, the client version came from Cursor's installer page, so six Run tests fetched it. The preload now fixes CURSOR_CLIENT_VERSION. Bun follows redirects inside fetch, past the guard. The guard makes each hop itself and refuses one that leaves the machine. A temp host cache stays registered until its cleanup finishes, so a test that times out while leaving it no longer hands its root on. A conversation-maintenance test created a quarantine file while the maintenance its own first read started could still recover and remove it. It waits for that maintenance first.
oakimov
force-pushed
the
hermetic-test-credentials
branch
from
November 10, 2026 19:57
4744b74 to
265f8d0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
plugin.configloads models: on a cache miss it reads the stored Cursor credential (authFromStore→readStoredAuth,src/plugin.ts) and callsdiscoverModels. Three tests inCursorPlugin shell result hooks(test/plugin.test.ts) call it insidewithTempHostCache, which is always a cache miss, and leave the data root alone. On a machine with a Cursor login they read the realauth.jsonand ran live model discovery.A full run with a recorder that blocks and logs every non-loopback
fetchand socket found two more callers of live Cursor:opencode2 setup > the aisdk sdk hook resolves the token per Run…sent its placeholder token toAvailableModels.pollForTokens > honours abort signalpolled/auth/pollon the default API host.The guard then found a third on CI: with no Cursor CLI installed the client version comes from
https://cursor.com/install(src/protocol/client-version.ts), and six Run tests fetched it.One slow discovery reached Bun's 5 s timeout, and 14 later tests plus the TMPDIR leftover check failed with it. Bun fails a timed-out test and keeps running its body.
withTempHostCachetherefore restored the process-wide cache root late: the scope entered meanwhile restored the removed directory as the root for the rest of the file.Fix
test/preload.tspointsXDG_DATA_HOMEinto the run's private TMPDIR and clearsOPENCODE_AUTH_CONTENT, as it already does forXDG_CACHE_HOME.openCodeGlobalDataDir(src/context/paths.ts) reads that variable first on every platform, so the store is empty unless a test writes a fake credential. Anything left in the data root fails the run.CURSOR_CLIENT_VERSION, so the client version depends on neither a local Cursor CLI install nor the installer page.test/network-guard.tsrefuses everyfetchand everynode:net/node:tls/node:http2connection that leaves the machine. Bun follows redirects insidefetch, so the guard makes each hop itself and checks the destination first. The preload'safterEachfails the test that tried, so code that swallows the refusal is caught too. It also fails a test that leavesXDG_DATA_HOMEorOPENCODE_AUTH_CONTENTchanged and puts them back. The guard covers the test process; processes a test spawns are outside it.test/host-cache.tsputs a temp host cache's roots back when its test ends (test/test-end.ts), so a test that times out in its body or while the cache is cleaned up no longer hands its root to later tests.test/conversation-maintenance.test.ts: one test created a quarantine file while the maintenance started by its own first read could still recover and remove it (theENOENTin this PR's first CI run). It now waits for that maintenance.fetchstub and a local server.No source change, no changelog entry.
Verification
Measured on macOS with a stored Cursor credential present,
bun test ./test/plugin.test.ts -t 'keeps soft-background Bash command original', three runs each:XDG_DATA_HOMEmainwithout live Cursor: a fixture credential under a fakeHOMEand a local server whose first model list answer is 7 s late give 1 timeout, 14 later failures and the leftover check intest/plugin.test.ts. With this branch the same setup passes 61/61, also when the credential comes through the caller'sXDG_DATA_HOMEorOPENCODE_AUTH_CONTENT.test/test-isolation.test.tscovers the guards in-process, redirects included, and runs four fixtures in a childbun test: a swallowed remotefetchfails its test; a test that leaves the store redirected fails and the next one is isolated again; a test that times out insidewithTempHostCache, in its body or during cleanup, fails alone. Against the previoustest/host-cache.tseach timeout fixture fails all four of its tests.bun run typecheck,bun run build, andbun test ./testthree times in a row, plus once with an empty home: 3418 pass, 5 skip, 0 fail across 127 files each time.