From 04173f1f83a7d367ae6d15d6c1e6711ed01a4b35 Mon Sep 17 00:00:00 2001 From: KodekaTeam Date: Sat, 18 Jul 2026 12:37:10 +0700 Subject: [PATCH] fix(git-providers): resolve legacy GitHub owners for repository loading --- .../providers/GithubProviderModal.tsx | 17 ++++++-- .../providers/GitlabProviderModal.tsx | 13 +++++- src/server/routes/git-providers.ts | 42 ++++++++++++++++++- 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/app/git/components/providers/GithubProviderModal.tsx b/src/app/git/components/providers/GithubProviderModal.tsx index 36e4c56..112ebd7 100644 --- a/src/app/git/components/providers/GithubProviderModal.tsx +++ b/src/app/git/components/providers/GithubProviderModal.tsx @@ -5,7 +5,6 @@ import { } from "@/app/settings/components/SettingsPrimitives"; import { type GithubProviderModalProps, - ProviderBadge, getProviderMeta, launchGithubManifestFlow, } from "./git-provider-shared"; @@ -117,7 +116,19 @@ export default function GithubProviderModal({ placeholder="Organization name" /> - ) : null} + ) : ( +
+ GitHub Username + + updateDraft("accountUsername", event.target.value) + } + placeholder="Your GitHub username" + /> +
+ )}
updateDraft("appName", event.target.value)} - placeholder={`Doktainer-${new Date().toISOString().split("T")[0].replace(/-/g, "")}-${Math.random().toString(36).slice(2, 10)}`} + placeholder="Doktainer-20260718-ab12cd34" />
diff --git a/src/app/git/components/providers/GitlabProviderModal.tsx b/src/app/git/components/providers/GitlabProviderModal.tsx index edb1a81..fdafd51 100644 --- a/src/app/git/components/providers/GitlabProviderModal.tsx +++ b/src/app/git/components/providers/GitlabProviderModal.tsx @@ -2,7 +2,6 @@ import { ExternalLink } from "lucide-react"; import { FieldLabel } from "@/app/settings/components/SettingsPrimitives"; import { type GitProviderModalBaseProps, - ProviderBadge, getProviderMeta, } from "./git-provider-shared"; import { markGitProviderCallbackIntent } from "@/lib/git-provider-callback-intent"; @@ -193,6 +192,18 @@ export default function GitlabProviderModal({ placeholder="my-org" /> + +
+ GitLab Username (Required Without Group) + + updateDraft("accountUsername", event.target.value) + } + placeholder="Your GitLab username" + /> +
); diff --git a/src/server/routes/git-providers.ts b/src/server/routes/git-providers.ts index fa9bbc1..4029c4b 100644 --- a/src/server/routes/git-providers.ts +++ b/src/server/routes/git-providers.ts @@ -1,7 +1,7 @@ import { FastifyInstance } from "fastify"; import { z } from "zod"; import prisma from "../lib/prisma"; -import { decrypt, encrypt } from "../lib/crypto"; +import { encrypt } from "../lib/crypto"; import { authenticate, requireRole } from "../middleware/auth"; import { auditLog } from "../services/audit.service"; import { verifyGitProviderConfiguration } from "../services/integration-verification.service"; @@ -170,6 +170,18 @@ function getProviderOwner(provider: GitProviderRecord) { ); } +function getGithubInstallationTargetId(installationUrl?: string | null) { + const rawUrl = toTrimmedValue(installationUrl); + if (!rawUrl) return ""; + + try { + const targetId = new URL(rawUrl).searchParams.get("target_id")?.trim(); + return targetId && /^\d+$/.test(targetId) ? targetId : ""; + } catch { + return ""; + } +} + function buildProviderFetchErrorMessage(args: { provider: GitProviderRecord["provider"]; resource: string; @@ -247,6 +259,32 @@ async function fetchJson( return json; } +async function resolveProviderOwner(provider: GitProviderRecord) { + const configuredOwner = getProviderOwner(provider); + if (configuredOwner || provider.provider !== "GITHUB") { + return configuredOwner; + } + + // GitHub's manifest flow stores the installation target account ID in the + // installation URL. Older personal-account records did not persist a + // username, so resolve the public login from that stable account ID. + const targetId = getGithubInstallationTargetId(provider.installationUrl); + if (!targetId) return ""; + + const baseUrl = normalizeBaseUrl(provider.providerUrl, "https://github.com"); + const apiBase = + baseUrl.toLowerCase() === "https://github.com" + ? "https://api.github.com" + : `${baseUrl}/api/v3`; + const payload = await fetchJson(`${apiBase}/user/${targetId}`, { + provider: provider.provider, + resource: "GitHub account", + }); + + if (!payload || typeof payload !== "object") return ""; + return toTrimmedValue((payload as { login?: string }).login); +} + function mapGithubRepositories(payload: unknown): GitProviderRepository[] { if (!Array.isArray(payload)) return []; @@ -468,7 +506,7 @@ function mapGiteaBranches( async function listRepositoriesForProvider( provider: GitProviderRecord, ): Promise { - const owner = getProviderOwner(provider); + const owner = await resolveProviderOwner(provider); if (!owner) { throw new Error( "Configure namespace, organization name, or account username on the Git provider before loading repositories",