Six Octokit call sites bypassed createGitHubClient() and constructed new Octokit(...) directly, so GH_API_URL / GITHUB_API_URL were silently ignored outside a handful of flows. GHES and GHEC-with-data-residency users hit https://api.github.com/... and got 401s even when the env var was set correctly (reported in #269, with the Test Connection button as the most visible symptom).
Routes every Octokit construction through createGitHubClient() so Enterprise endpoints work everywhere. Makes the helper's token param optional to preserve the one unauthenticated caller (public-repo sync).
Call sites fixed
File
Flow
src/pages/api/github/test-connection.ts
GitHub "Test Connection" button (the reported failure)
Side benefit: scheduler + sync paths now also get throttling, rate-limit tracking, and the standard gitea-mirror/<version> User-Agent — which were previously missing.
Test plan
bun test — 231 pass, 0 fail (was 229 pass / 2 fail before the test-connection test update; see note below)
bun run build — clean
Manual: unset GH_API_URL → confirm standard github.com flows still work (regression)
Manual (requires GHES / GHEC-data-residency instance): set GH_API_URL=https://api.TENANT.ghe.com, hit Test Connection in the GitHub settings panel, confirm request goes to the configured host and authenticates
Note on the test-connection test file
The existing test mocked @octokit/rest directly, but github.ts captures the Octokit reference at module init when wrapping it with the throttling plugin, so by the time the mock registers the real reference is already baked into the closure. Retargeted the mock to @/lib/github (mocking at the helper layer) so it intercepts correctly. Same test surface, same assertions.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
## 📋 Pull Request Information
**Original PR:** https://github.com/RayLabsHQ/gitea-mirror/pull/273
**Author:** [@arunavo4](https://github.com/arunavo4)
**Created:** 4/20/2026
**Status:** ✅ Merged
**Merged:** 4/20/2026
**Merged by:** [@arunavo4](https://github.com/arunavo4)
**Base:** `main` ← **Head:** `fix/gh-api-url-enterprise-routing`
---
### 📝 Commits (2)
- [`221157a`](https://github.com/RayLabsHQ/gitea-mirror/commit/221157a29f1725a3a800c2792f4c67f24cb384f3) fix: honor GH_API_URL across all Octokit call sites
- [`f96d625`](https://github.com/RayLabsHQ/gitea-mirror/commit/f96d6253fc41df95ec574bdf934135ddcfc425c0) fix: address review findings
### 📊 Changes
**6 files changed** (+81 additions, -75 deletions)
<details>
<summary>View changed files</summary>
📝 `src/lib/gitea-enhanced.ts` (+4 -5)
📝 `src/lib/scheduler-service.ts` (+13 -15)
📝 `src/pages/api/github/test-connection.test.ts` (+46 -44)
📝 `src/pages/api/github/test-connection.ts` (+5 -5)
📝 `src/pages/api/sync/repository.ts` (+10 -1)
📝 `src/tests/test-metadata-mirroring.ts` (+3 -5)
</details>
### 📄 Description
## Summary
- Six Octokit call sites bypassed `createGitHubClient()` and constructed `new Octokit(...)` directly, so `GH_API_URL` / `GITHUB_API_URL` were silently ignored outside a handful of flows. GHES and GHEC-with-data-residency users hit `https://api.github.com/...` and got 401s even when the env var was set correctly (reported in #269, with the **Test Connection** button as the most visible symptom).
- Routes every Octokit construction through `createGitHubClient()` so Enterprise endpoints work everywhere. Makes the helper's `token` param optional to preserve the one unauthenticated caller (public-repo sync).
## Call sites fixed
| File | Flow |
|---|---|
| `src/pages/api/github/test-connection.ts` | GitHub "Test Connection" button (the reported failure) |
| `src/pages/api/sync/repository.ts` | Public-repo add-by-URL sync |
| `src/lib/gitea-enhanced.ts` | Force-push detection + metadata Octokit (releases/issues/PRs/labels) |
| `src/lib/scheduler-service.ts` | Auto-discovery, auto-mirror, auto-start (3 constructions) |
| `src/tests/test-metadata-mirroring.ts` | Dev harness, updated for consistency |
Side benefit: scheduler + sync paths now also get throttling, rate-limit tracking, and the standard `gitea-mirror/<version>` User-Agent — which were previously missing.
## Test plan
- [x] `bun test` — 231 pass, 0 fail (was 229 pass / 2 fail before the test-connection test update; see note below)
- [x] `bun run build` — clean
- [ ] Manual: unset `GH_API_URL` → confirm standard github.com flows still work (regression)
- [ ] Manual (requires GHES / GHEC-data-residency instance): set `GH_API_URL=https://api.TENANT.ghe.com`, hit **Test Connection** in the GitHub settings panel, confirm request goes to the configured host and authenticates
### Note on the test-connection test file
The existing test mocked `@octokit/rest` directly, but `github.ts` captures the `Octokit` reference at module init when wrapping it with the throttling plugin, so by the time the mock registers the real reference is already baked into the closure. Retargeted the mock to `@/lib/github` (mocking at the helper layer) so it intercepts correctly. Same test surface, same assertions.
Fixes #269
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/RayLabsHQ/gitea-mirror/pull/273
Author: @arunavo4
Created: 4/20/2026
Status: ✅ Merged
Merged: 4/20/2026
Merged by: @arunavo4
Base:
main← Head:fix/gh-api-url-enterprise-routing📝 Commits (2)
221157afix: honor GH_API_URL across all Octokit call sitesf96d625fix: address review findings📊 Changes
6 files changed (+81 additions, -75 deletions)
View changed files
📝
src/lib/gitea-enhanced.ts(+4 -5)📝
src/lib/scheduler-service.ts(+13 -15)📝
src/pages/api/github/test-connection.test.ts(+46 -44)📝
src/pages/api/github/test-connection.ts(+5 -5)📝
src/pages/api/sync/repository.ts(+10 -1)📝
src/tests/test-metadata-mirroring.ts(+3 -5)📄 Description
Summary
createGitHubClient()and constructednew Octokit(...)directly, soGH_API_URL/GITHUB_API_URLwere silently ignored outside a handful of flows. GHES and GHEC-with-data-residency users hithttps://api.github.com/...and got 401s even when the env var was set correctly (reported in #269, with the Test Connection button as the most visible symptom).createGitHubClient()so Enterprise endpoints work everywhere. Makes the helper'stokenparam optional to preserve the one unauthenticated caller (public-repo sync).Call sites fixed
src/pages/api/github/test-connection.tssrc/pages/api/sync/repository.tssrc/lib/gitea-enhanced.tssrc/lib/scheduler-service.tssrc/tests/test-metadata-mirroring.tsSide benefit: scheduler + sync paths now also get throttling, rate-limit tracking, and the standard
gitea-mirror/<version>User-Agent — which were previously missing.Test plan
bun test— 231 pass, 0 fail (was 229 pass / 2 fail before the test-connection test update; see note below)bun run build— cleanGH_API_URL→ confirm standard github.com flows still work (regression)GH_API_URL=https://api.TENANT.ghe.com, hit Test Connection in the GitHub settings panel, confirm request goes to the configured host and authenticatesNote on the test-connection test file
The existing test mocked
@octokit/restdirectly, butgithub.tscaptures theOctokitreference at module init when wrapping it with the throttling plugin, so by the time the mock registers the real reference is already baked into the closure. Retargeted the mock to@/lib/github(mocking at the helper layer) so it intercepts correctly. Same test surface, same assertions.Fixes #269
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.