From ba4b94790c41abbc0b31c92b9b21ec136fb5b33b Mon Sep 17 00:00:00 2001 From: mawkone Date: Mon, 9 Mar 2026 18:05:09 -0700 Subject: [PATCH] feat(mirror): support GitHub PAT for private repo mirroring Accept optional github_token in POST /api/mirror and inject it into the git clone URL so private repos can be cloned without interactive auth. Made-with: Cursor --- src/server.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/server.ts b/src/server.ts index 69f51a6..131d307 100644 --- a/src/server.ts +++ b/src/server.ts @@ -97,10 +97,11 @@ app.get('/health', (_req: Request, res: Response) => { // --------------------------------------------------------------------------- app.post('/api/mirror', async (req: Request, res: Response) => { - const { github_url, gitea_repo, project_name } = req.body as { + const { github_url, gitea_repo, project_name, github_token } = req.body as { github_url?: string; gitea_repo?: string; // e.g. "mark/opsos" project_name?: string; + github_token?: string; // PAT for private repos }; if (!github_url || !gitea_repo) { @@ -132,8 +133,14 @@ app.post('/api/mirror', async (req: Request, res: Response) => { console.log(`[mirror] Cloning ${github_url} → ${tmpDir}`); fs.mkdirSync(tmpDir, { recursive: true }); + // Build authenticated clone URL for private repos + let cloneUrl = github_url; + if (github_token) { + cloneUrl = github_url.replace('https://', `https://${github_token}@`); + } + // Mirror-clone the GitHub repo (preserves all branches + tags) - execSync(`git clone --mirror "${github_url}" "${tmpDir}/.git"`, { + execSync(`git clone --mirror "${cloneUrl}" "${tmpDir}/.git"`, { stdio: 'pipe', timeout: 120_000 });