From be8d3dccb68be5c89cad09226d851372316b6be0 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:16:28 -0700 Subject: [PATCH] test(unit): isolate loopover-mcp/miner tests from real machine state Three test/unit/ files pass or fail depending on the host machine rather than the working tree: local-branch.test.ts compared against the raw os.tmpdir() path instead of safeResolvedPath's realpathSync-resolved form (diverges on macOS, where tmpdir lives under a /var -> /private/var symlink), and miner-init-verify-token.test.ts / miner-self-review- context.test.ts didn't isolate env/loopoverAuth, so resolveGitHubToken / resolveLoopoverBackendSession fell through to a real ~/.config/loopover/config.json on any machine that has run `loopover-mcp login`, firing an extra concurrent fetch that raced with and corrupted other captured calls/headers/timeouts. Closes #7512 --- test/unit/local-branch.test.ts | 12 +++-- test/unit/miner-init-verify-token.test.ts | 11 +++++ test/unit/miner-self-review-context.test.ts | 51 ++++++++++++--------- 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/test/unit/local-branch.test.ts b/test/unit/local-branch.test.ts index 0fe02c419..9865cc050 100644 --- a/test/unit/local-branch.test.ts +++ b/test/unit/local-branch.test.ts @@ -1,5 +1,5 @@ import { execFileSync } from "node:child_process"; -import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; +import { mkdtempSync, mkdirSync, realpathSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { pathToFileURL } from "node:url"; @@ -2472,19 +2472,23 @@ describe("local MCP git metadata collection (#7329 coverage)", () => { const root = join(tempDir, "root"); mkdirSync(join(root, "nested"), { recursive: true }); const roots = [{ uri: pathToFileURL(root).href }]; + // resolveWorkspaceCwd resolves symlinks via realpathSync (safeResolvedPath), so the expected path must + // too -- on macOS, os.tmpdir() lives under /var/folders/..., itself a symlink to /private/var/folders/.... + const expectedNested = realpathSync(join(root, "nested")); const relative = resolveWorkspaceCwd({ cwd: "nested", workspaceRoots: roots }); - expect(relative).toMatchObject({ cwd: join(root, "nested"), rootsAvailable: true }); + expect(relative).toMatchObject({ cwd: expectedNested, rootsAvailable: true }); const absolute = resolveWorkspaceCwd({ cwd: join(root, "nested"), workspaceRoots: roots }); - expect(absolute).toMatchObject({ cwd: join(root, "nested"), rootsAvailable: true }); + expect(absolute).toMatchObject({ cwd: expectedNested, rootsAvailable: true }); }); it("normalizeMcpWorkspaceRoots ignores a root with a non-string uri and dedupes repeated paths", async () => { const { normalizeMcpWorkspaceRoots } = await import("../../packages/loopover-mcp/lib/local-branch.js"); tempDir = mkdtempSync(join(tmpdir(), "loopover-local-")); const uri = pathToFileURL(tempDir).href; - expect(normalizeMcpWorkspaceRoots([{ uri: 42 as unknown as string }, { uri }, { uri }])).toEqual([{ path: tempDir }]); + // normalizeMcpWorkspaceRoots resolves symlinks via realpathSync (safeResolvedPath) -- see the note above. + expect(normalizeMcpWorkspaceRoots([{ uri: 42 as unknown as string }, { uri }, { uri }])).toEqual([{ path: realpathSync(tempDir) }]); expect(normalizeMcpWorkspaceRoots(undefined)).toEqual([]); }); diff --git a/test/unit/miner-init-verify-token.test.ts b/test/unit/miner-init-verify-token.test.ts index a4f6f1ad7..227016c0f 100644 --- a/test/unit/miner-init-verify-token.test.ts +++ b/test/unit/miner-init-verify-token.test.ts @@ -9,10 +9,21 @@ const tempDirs = new Set(); function makeTempEnv() { const configDir = mkdtempSync(join(tmpdir(), "loopover-miner-init-")); tempDirs.add(configDir); + // Isolate from any real loopover-mcp session on disk: runInit's --verify-token path resolves a GitHub + // token via resolveGitHubToken (packages/loopover-miner/lib/github-token-resolution.js), which falls back + // to a live session-token fetch when ~/.config/loopover/config.json (or an inherited GITHUB_TOKEN) has + // real credentials -- a contributor machine with `loopover-mcp login` already run would otherwise make an + // extra fetch call and read a real token into these tests instead of the mocked one. + const loopoverConfigDir = mkdtempSync(join(tmpdir(), "loopover-miner-init-mcp-config-")); + tempDirs.add(loopoverConfigDir); return { env: { ...process.env, LOOPOVER_MINER_CONFIG_DIR: configDir, + LOOPOVER_CONFIG_DIR: loopoverConfigDir, + LOOPOVER_CONFIG_PATH: undefined, + XDG_CONFIG_HOME: undefined, + GITHUB_TOKEN: undefined, }, configDir, dbPath: join(configDir, "laptop-state.sqlite3"), diff --git a/test/unit/miner-self-review-context.test.ts b/test/unit/miner-self-review-context.test.ts index 2bf5f9275..75ed76760 100644 --- a/test/unit/miner-self-review-context.test.ts +++ b/test/unit/miner-self-review-context.test.ts @@ -143,6 +143,7 @@ describe("fetchSelfReviewContext (#5145)", () => { contributorLogin: "miner-bot", linkedIssues: [7], fetchImpl: fetchImpl as never, + loopoverAuth: null, }); expect(result.repo).toEqual({ @@ -225,7 +226,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "api.gittensor.io/miners": () => jsonResponse([]), }); - const result = await fetchSelfReviewContext("acme/widgets", { linkedIssues: [7], fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { linkedIssues: [7], fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.inDuplicateCluster).toBe(true); }); @@ -238,7 +239,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "api.gittensor.io/miners": () => jsonResponse([]), }); - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.issueQuality?.issues).toHaveLength(1); expect(result.issueQuality?.issues[0]).toMatchObject({ number: 7, status: expect.any(String) }); expect(result.issueQuality?.repoFullName).toBe("acme/widgets"); @@ -260,7 +261,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "api.gittensor.io/miners": () => jsonResponse([]), }); - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.issues[0]?.linkedPrs).toEqual([]); }); @@ -273,7 +274,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "api.gittensor.io/miners": () => jsonResponse([]), }); - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.issues[0]?.linkedPrs).toEqual([501]); }); it("returns false for inDuplicateCluster when no linkedIssues are supplied", async () => { @@ -285,7 +286,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "api.gittensor.io/miners": () => jsonResponse([]), }); - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.inDuplicateCluster).toBe(false); }); @@ -298,7 +299,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "api.gittensor.io/miners": () => jsonResponse([]), }); - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.issues.map((issue) => issue.number)).toEqual([7]); }); @@ -318,7 +319,7 @@ describe("fetchSelfReviewContext (#5145)", () => { return jsonResponse(null, 404); }; - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, perPage: 2 }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, perPage: 2, loopoverAuth: null }); expect(result.issues.map((issue) => issue.number)).toEqual([11, 12, 21, 22, 99]); expect(issuePage).toBe(3); }); @@ -337,7 +338,7 @@ describe("fetchSelfReviewContext (#5145)", () => { return jsonResponse(null, 404); }; - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, perPage: 1 }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, perPage: 1, loopoverAuth: null }); expect(result.issues.map((issue) => issue.number)).toEqual([7]); }); @@ -350,7 +351,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "api.gittensor.io/miners": () => jsonResponse([]), }); - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.repo).toBeNull(); }); @@ -368,7 +369,7 @@ describe("fetchSelfReviewContext (#5145)", () => { return jsonResponse(null, 404); }; - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(requestedPaths).toEqual([ "https://raw.githubusercontent.com/acme/widgets/HEAD/.loopover.yml", "https://raw.githubusercontent.com/acme/widgets/HEAD/.github/loopover.yml", @@ -392,7 +393,7 @@ describe("fetchSelfReviewContext (#5145)", () => { return jsonResponse(null, 404); }; - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(manifestRequests).toBe(4); expect(result.manifest.present).toBe(false); expect(result.manifest.warnings).toEqual([]); @@ -410,7 +411,7 @@ describe("fetchSelfReviewContext (#5145)", () => { return jsonResponse(null, 404); }; - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(cancelCount).toBe(4); expect(result.manifest.present).toBe(false); }); @@ -429,7 +430,7 @@ describe("fetchSelfReviewContext (#5145)", () => { return jsonResponse(null, 404); }; - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(requestedPaths).toHaveLength(1); expect(result.manifest.gate?.duplicates).toBe("advisory"); }); @@ -448,7 +449,7 @@ describe("fetchSelfReviewContext (#5145)", () => { return jsonResponse(null, 404); }; - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.confirmedContributor).toBe(false); expect(minersCalled).toBe(false); }); @@ -461,7 +462,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "/repos/acme/widgets": () => jsonResponse(REPO_PAYLOAD), "raw.githubusercontent.com": () => jsonResponse(null, 404), }); - expect((await fetchSelfReviewContext("acme/widgets", { contributorLogin: "Miner-Bot", fetchImpl: miss as never })).confirmedContributor).toBe(false); + expect((await fetchSelfReviewContext("acme/widgets", { contributorLogin: "Miner-Bot", fetchImpl: miss as never, loopoverAuth: null })).confirmedContributor).toBe(false); const notOk = routedFetch({ "api.gittensor.io/miners": () => jsonResponse(null, 500), @@ -470,7 +471,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "/repos/acme/widgets": () => jsonResponse(REPO_PAYLOAD), "raw.githubusercontent.com": () => jsonResponse(null, 404), }); - expect((await fetchSelfReviewContext("acme/widgets", { contributorLogin: "miner-bot", fetchImpl: notOk as never })).confirmedContributor).toBe(false); + expect((await fetchSelfReviewContext("acme/widgets", { contributorLogin: "miner-bot", fetchImpl: notOk as never, loopoverAuth: null })).confirmedContributor).toBe(false); const throwing = async (url: string) => { if (url.includes("api.gittensor.io/miners")) throw new Error("network down"); @@ -480,7 +481,7 @@ describe("fetchSelfReviewContext (#5145)", () => { if (url.includes("raw.githubusercontent.com")) return jsonResponse(null, 404); return jsonResponse(null, 404); }; - expect((await fetchSelfReviewContext("acme/widgets", { contributorLogin: "miner-bot", fetchImpl: throwing as never })).confirmedContributor).toBe(false); + expect((await fetchSelfReviewContext("acme/widgets", { contributorLogin: "miner-bot", fetchImpl: throwing as never, loopoverAuth: null })).confirmedContributor).toBe(false); }); it("matches a confirmed contributor case-insensitively", async () => { @@ -491,7 +492,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "/repos/acme/widgets": () => jsonResponse(REPO_PAYLOAD), "raw.githubusercontent.com": () => jsonResponse(null, 404), }); - const result = await fetchSelfReviewContext("acme/widgets", { contributorLogin: "miner-bot", fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { contributorLogin: "miner-bot", fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.confirmedContributor).toBe(true); }); @@ -510,7 +511,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "api.gittensor.io/miners": () => jsonResponse([]), }); - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.pullRequests[0]?.linkedIssues).toEqual([7]); }); @@ -523,7 +524,7 @@ describe("fetchSelfReviewContext (#5145)", () => { "api.gittensor.io/miners": () => jsonResponse([]), }); - const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + const result = await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(result.pullRequests.find((pr) => pr.number === 51)?.mergeableState).toBe("dirty"); expect(result.pullRequests.find((pr) => pr.number === 52)?.mergeableState).toBeNull(); }); @@ -563,7 +564,11 @@ describe("fetchSelfReviewContext (#5145)", () => { if (url.includes("api.gittensor.io/miners")) return jsonResponse([]); return jsonResponse(null, 404); }; - await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never }); + // loopoverAuth: null forces the ORB live-gate-thresholds probe off (#6487) -- without it, a real + // loopover-mcp session recorded on disk (e.g. from `loopover-mcp login` on a contributor's machine) + // would fire an extra concurrent fetch whose "Bearer " header could race with and + // overwrite capturedAuth, since its URL also matches this test's own "/repos/acme/widgets" routing. + await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, loopoverAuth: null }); expect(capturedAuth).toBe("Bearer env-token"); } finally { if (original === undefined) delete process.env.GITHUB_TOKEN; @@ -584,7 +589,9 @@ describe("fetchSelfReviewContext (#5145)", () => { return jsonResponse(null, 404); }; - await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, contributorLogin: "miner-bot" }); + // loopoverAuth: null keeps this test's call count and 10s-default assertion honest -- see the note on + // the "defaults GITHUB_TOKEN" test above for why an unforced probe is a real-environment hazard here too. + await fetchSelfReviewContext("acme/widgets", { fetchImpl: fetchImpl as never, contributorLogin: "miner-bot", loopoverAuth: null }); // repo + issues + pulls (githubGetJson) + 4 manifest candidates + 1 contributor lookup = 8 calls, every one bounded. expect(capturedSignals.length).toBeGreaterThanOrEqual(7);