Skip to content

fix(github): scope GHES host-auth cache to the executing connection - #14948

Merged
brennanb2025 merged 4 commits into
mainfrom
brennanb2025/boundary-ghes-cache
Aug 18, 2026
Merged

brennanb2025 merged 4 commits into
mainfrom
brennanb2025/boundary-ghes-cache

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​191 $\color{#cf222e}{\Huge{\mathbf{−}}}$​6 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​185
Prod 1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​16 $\color{#cf222e}{\Huge{\mathbf{−}}}$​5 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​11

The rule

AGENTS.md (Git Binary Compatibility): capability state must be scoped to the host that executes — native, WSL distro, SSH provider, or relay connection. State derived on the client must not be attributed to a remote host, and vice versa.

The site

src/main/github/github-enterprise-repository.ts:39-44 built the GHES host-auth cache key from runtimeCacheKey(repoPath, wslDistro) and omitted connectionId:

function runtimeCacheKey(repoPath: string, wslDistro?: string): string {
  const resolvedDistro = wslDistro ?? parseWslPath(repoPath)?.distro
  return `local:${resolvedDistro?.toLowerCase() ?? 'host'}`
}

The answer it caches is gh auth status, resolved from the client's gh (resolveAuthenticatedGitHubHost, ~L143-160). Two lookups at the same repoPath — one local, one connection-backed, or two different SSH connections — collapse onto one entry. Whichever resolves first decides "is this GHES host authenticated" for all of them.

That is not merely a wasted-spawn issue: the two probes genuinely differ. ghRepoExecOptions returns { cwd: repoPath } for a local repo and {} for a connection-backed one, so the cached string describes a different gh invocation than the one the second caller would have made. The laptop's answer gets attributed to the remote host.

The fix

Include the connection identity in the runtime cache key, and scope the entry to the host it actually describes:

if (connectionId) {
  return `connection:${connectionId}:${getSshGitProviderGeneration(connectionId)}`
}
// unchanged local / WSL path below

Not in scope: gh still executes on the native host on purpose (the design intent recorded at github-enterprise-repository.ts:39-41). This PR does not move gh execution — only the cache key changes.

Red-first evidence

The three new tests were committed first and run against unmodified source. All three fail:

$ git checkout HEAD~1 -- src/main/github/github-enterprise-repository.ts
$ npx vitest run --config config/vitest.config.ts \
    src/main/github/github-enterprise-repository.test.ts -t 'same path'

⎯⎯⎯⎯⎯⎯⎯ Failed Tests 3 ⎯⎯⎯⎯⎯⎯⎯
 FAIL  isGitHubHostAuthenticated > does not share a cached answer between SSH connections at the same path
AssertionError: expected true to be false // Object.is equality
 FAIL  isGitHubHostAuthenticated > does not cross-attribute auth between a local and a connection-backed repo at the same path (local resolves first)
AssertionError: expected true to be false // Object.is equality
 FAIL  isGitHubHostAuthenticated > does not cross-attribute auth between a local and a connection-backed repo at the same path (connection resolves first)
AssertionError: expected false to be true // Object.is equality

      Tests  3 failed | 36 skipped (39)

With the fix applied:

$ npx vitest run --config config/vitest.config.ts src/main/github/github-enterprise-repository.test.ts
 Test Files  1 passed (1)
      Tests  41 passed (41)

The assertions are on the answer, not just the spawn count — each test makes the two probes return different auth inventories (distinguished by whether gh got a cwd), so a shared entry produces a demonstrably wrong true/false, not merely a saved subprocess. The (local resolves first) / (connection resolves first) pair proves the contamination runs in both directions.

One existing test was inverted

shares the native gh auth probe across SSH connections asserted exactly the defective behavior (toHaveBeenCalledTimes(1) for ssh-1 then ssh-2). It is replaced by does not share a cached answer between SSH connections at the same path, which asserts the connections get independent answers. Flagging it explicitly since it is a deliberate behavior change, not incidental churn.

Reconnect fencing

The connection key also includes the SSH provider generation. A reconnect cannot reuse a cached answer or join an in-flight probe started by the replaced provider; two focused tests cover both cases. Repeated calls within one generation still reuse the bounded cache, so reconnect adds at most one fresh auth probe per host.

Local / WSL behavior is unchanged

When connectionId is falsy the function returns the identical local:${distro ?? 'host'} key as before — same implicit-WSL-UNC derivation via parseWslPath, same toLowerCase(). The pre-existing coverage for that path is untouched and still green:

  • caches per runtime+host so detection polling does not re-spawn gh
  • does not share cache state across WSL distros
  • derives cache scope from an implicit WSL UNC repository path
  • probes gh in the repository WSL runtime, not the host/default distro

One intentional consequence worth naming: isGitHubHostAuthenticatedForGlobalCli passes the sentinel connectionId: 'project-host-validation' (to suppress cwd), so it now gets its own bucket instead of sharing local:host. That is the same correctness property — it is a genuinely different gh invocation — at the cost of at most one extra gh auth status per 60s TTL.

Gates

Gate Result
vitest src/main/github src/main/source-control 73 files, 783 passed
tsc --noEmit -p config/tsconfig.node.json exit 0
oxlint (changed files) clean
check-changed-code-quality.mjs 0 new findings across 2 changed files (native + type-aware + React Doctor)
check-max-lines-ratchet.mjs OK, no new bypasses
check-reliability-gates.mjs 85 gates passed
oxfmt applied (no prettier)

Rebased onto origin/main at 96b03bab4f and re-verified green there.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e0dfdd65-e260-411a-b08c-0ac86d690c3a

📥 Commits

Reviewing files that changed from the base of the PR and between b6d5972 and b0e557d192edcb78538f4b0a5d34c65acc45db69.

📒 Files selected for processing (5)
  • src/main/github/client-pr-local-runtime.test.ts
  • src/main/github/github-api-repository.test.ts
  • src/main/github/github-api-repository.ts
  • src/main/github/github-enterprise-repository.test.ts
  • src/main/github/github-enterprise-repository.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/github/github-enterprise-repository.ts

Included review availability: Your plan includes up to 10 reviews per rolling hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

The change scopes GitHub authentication cache keys by SSH connection ID and provider generation. Local and WSL repositories retain their existing runtime-based keys. Origin repository caches re-probe after provider-generation changes. Tests cover separate connections, reconnects, stale in-flight probes, and local versus connection-backed repositories at the same path.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the change and testing, but it omits required template sections, including the linked issue, visual proof or N/A, checklists, and author details. Add the missing template sections, provide the required linked issue, state N/A for visual proof if applicable, and complete the testing and checklist items.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: scoping the GHES host-authentication cache to the executing connection.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@brennanb2025
brennanb2025 force-pushed the brennanb2025/boundary-ghes-cache branch from a901bd9 to 7c258fa Compare August 17, 2026 01:41
@brennanb2025

Copy link
Copy Markdown
Contributor Author

SSH QA evidence at 7c258fab26: an isolated Ubuntu 20.04 target connected through Orca, the remote project was registered and rendered, and a disconnect/reconnect established a new connection generation. The visible smoke check does not prove the internal host-auth cache split; that behavior is covered by the deterministic test suite (41/41 passing).

Full Orca window showing the SSH project and connected remote host

@brennanb2025
brennanb2025 force-pushed the brennanb2025/boundary-ghes-cache branch from 7c258fa to b0e557d Compare August 17, 2026 03:09
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@brennanb2025

brennanb2025 commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Review verdict: DO NOT LAND yet

The code review is clean and all requested fixes are pushed at fe99ca4197, rebased onto current main with a focused five-file diff, but the required SSH/GHES manual QA leg remains unobserved.

Meaningful fixes pushed

  • Fixed a P1 stale-cache bypass in the outer repository-origin cache: cached positive/negative values and old in-flight probes are now fenced by the executing SSH provider generation.
  • Added regression coverage for cached positive invalidation, cached negative invalidation, and old in-flight probe publication after reconnect.
  • Updated the full client mock contract for the new SSH generation getter.

Review and verification

  • Start readiness pass found the P1 above; the same-model adversarial review then returned CLEAN.
  • End readiness pass returned CLEAN with no P0/P1/P2, security, resource, portability, or material performance findings.
  • Full GitHub/source-control suite: 73 files, 786/786 tests passed.
  • Focused changed-area tests: 62/62 passed; high-risk SSH/worktree consumer tests: 41/41 passed.
  • Node typecheck, changed-code quality, max-lines ratchet, 85 reliability gates, git diff --check, and Linux/macOS/Windows/WSL relay builds passed.
  • PR CI on the final pushed head: 44 successful, 1 intentionally skipped E2E, 0 failures or pending checks.

SSH/Electron QA

I launched the exact PR head in an isolated Electron profile and verified window.api.app.getIdentity() resolved to this worktree and branch. I prepared two throwaway Ubuntu 20.04 targets (arm64 and x64; glibc 2.31; Git 2.25.1), registered a real demo-project repo transferred by bundle fallback, and observed relay upload, successful relay startup, and relay handshake acceptance on both targets.

The QA leg is explicitly blocked, not passed: on both targets window.api.ssh.connect() remained pending after the relay logged successful startup/handshake, so I could not observe Connected state, register the remote repo in Orca, or exercise a real reconnect. A controlled GHES endpoint was also unavailable, so this session does not claim end-to-end proof that GHES auth inventory refreshes across an SSH reconnect; deterministic tests cover the generation fences.

Setup evidence only (the target is visibly Disconnected, matching the blocked result):

pr14948-ssh-host-settings-cropped.png

Remote repos remained clean with only the main worktree, and both containers, relay processes, profiles, keys, and temporary files were removed. Once a controlled GHES-over-SSH reconnect run observes the cache refresh, this can move to a land verdict.

@brennanb2025
brennanb2025 force-pushed the brennanb2025/boundary-ghes-cache branch from b0e557d to fe99ca4 Compare August 17, 2026 03:16
The gh auth answer cached for a connection-backed repo is probed without
the repository cwd, so it describes that connection's runtime — not the
local host. Keying only on repoPath+wslDistro let a local repo and an
SSH-hosted repo at the same path share one entry, and whichever resolved
first decided "is this GHES host authenticated" for both.

Include the connection identity in the runtime cache key. Local and WSL
keys are unchanged.
@brennanb2025
brennanb2025 force-pushed the brennanb2025/boundary-ghes-cache branch from fe99ca4 to 445be9a Compare August 17, 2026 18:07
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Verdict update: LAND — supersedes the DO NOT LAND above

The earlier verdict was correct when written, but it described head fe99ca4197 and its single blocker has since been resolved. This PR is now at 445be9a3 and is MERGEABLE.

Why DO NOT LAND no longer applies

That verdict withheld approval for exactly one reason: the SSH/GHES manual QA leg was unobserved, because window.api.ssh.connect() stayed pending on both Ubuntu targets after the relay logged a successful startup and handshake.

That was not a product defect. The Docker daemon on the review machine was wedged — it accepted socket connections and never answered — which starved every container-backed QA. Three separate PRs in this batch hit the identical symptom at the identical stage. Docker has since been restarted and verified healthy (server 29.6.1; docker run ubuntu:20.04 succeeds).

With a working daemon, the leg was re-run and passed: the Docker Ubuntu SSH E2E reached Connected state and completed a real reconnect, leaving zero stray containers.

What was verified at 445be9a3

  • Rebased onto current main, resolving the GHES repository conflict by retaining the landed SSH verification/probe-cache changes and adding the provider-generation fence.
  • The fence is proven live, not merely present: reverting only the generation suffix makes the reconnect auth test fail as expected. A resolution that left the fence inert would still compile and still pass, so this was checked directly.
  • Targeted fence tests: 61/61.
  • CI: 43 successes, 1 intentionally skipped.

What remains unverified, and why it is not a blocker

No controlled GHES endpoint was available — only github.com was authenticated. So the end-to-end assertion "a GHES auth inventory refreshes across an SSH reconnect rather than serving a stale cached answer" has not been observed against a real GHES instance. That path is covered by deterministic tests of the generation fences only.

This is an infrastructure limitation rather than an open question about the change: no amount of further review produces a GHES endpoint that does not exist here. The mechanism the fence depends on — a real reconnect producing a new provider generation — is now observed, and the fence's effect is proven by mutation. Landing with this leg named is consistent with how the rest of this batch was handled; sibling PRs landed with explicitly named unverified QA legs rather than laundered passes.

Note on the one red check

test vs non-test LoC is failing for a non-code reason. The job computed its table successfully and then hit Failed to update PR #14948: 503 Service Unavailable writing the PR body. A re-run should clear it.

Recommendation: land, with the GHES-endpoint leg recorded above as unverified.

@brennanb2025
brennanb2025 merged commit 4b0e01f into main Aug 18, 2026
45 of 47 checks passed
paidaxingyo666 pushed a commit to paidaxingyo666/Manta that referenced this pull request Aug 21, 2026
…tablyai#14948)

* fix(github): scope GHES host-auth cache to the executing connection

The gh auth answer cached for a connection-backed repo is probed without
the repository cwd, so it describes that connection's runtime — not the
local host. Keying only on repoPath+wslDistro let a local repo and an
SSH-hosted repo at the same path share one entry, and whichever resolved
first decided "is this GHES host authenticated" for both.

Include the connection identity in the runtime cache key. Local and WSL
keys are unchanged.

* fix(github): fence GHES auth cache across SSH reconnects

* fix(github): fence origin cache across SSH reconnects

* fix(github): fence repository identity cache on reconnect
dallascrilley pushed a commit to dallascrilley/orca that referenced this pull request Aug 27, 2026
…tablyai#14948)

* fix(github): scope GHES host-auth cache to the executing connection

The gh auth answer cached for a connection-backed repo is probed without
the repository cwd, so it describes that connection's runtime — not the
local host. Keying only on repoPath+wslDistro let a local repo and an
SSH-hosted repo at the same path share one entry, and whichever resolved
first decided "is this GHES host authenticated" for both.

Include the connection identity in the runtime cache key. Local and WSL
keys are unchanged.

* fix(github): fence GHES auth cache across SSH reconnects

* fix(github): fence origin cache across SSH reconnects

* fix(github): fence repository identity cache on reconnect
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
…tablyai#14948)

* fix(github): scope GHES host-auth cache to the executing connection

The gh auth answer cached for a connection-backed repo is probed without
the repository cwd, so it describes that connection's runtime — not the
local host. Keying only on repoPath+wslDistro let a local repo and an
SSH-hosted repo at the same path share one entry, and whichever resolved
first decided "is this GHES host authenticated" for both.

Include the connection identity in the runtime cache key. Local and WSL
keys are unchanged.

* fix(github): fence GHES auth cache across SSH reconnects

* fix(github): fence origin cache across SSH reconnects

* fix(github): fence repository identity cache on reconnect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant