From 5972cd2fbc1f46f5e0adb70ef6f5fa40e0e783d7 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 2 Sep 2026 04:06:54 -0500 Subject: [PATCH] =?UTF-8?q?auditor:=20repoint=20Gitea=20client=20at=20git.?= =?UTF-8?q?warren.help=20=E2=80=94=20agentview=20host=20is=20dead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git.agentview.dev has served a Traefik default cert + API 404 since Aug 25 (VPS consolidation moved repos to warren); listOpenPrs failed every 90s cycle since. Host default moves to git.warren.help and auth now resolves per-host from ~/.git-credentials with fallback to the origin remote's embedded credentials, sent as Basic (works for PAT or password). Verified live: /api/v1/user auths as profit, pulls list 200s. Co-Authored-By: Claude Fable 5 --- auditor/gitea.ts | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/auditor/gitea.ts b/auditor/gitea.ts index 2b20d57..2d897e8 100644 --- a/auditor/gitea.ts +++ b/auditor/gitea.ts @@ -9,28 +9,42 @@ import { readFile } from "node:fs/promises"; import type { PrSnapshot } from "./types.ts"; -const HOST = process.env.GITEA_HOST ?? "https://git.agentview.dev"; +// 2026-09-02: repo home moved to git.warren.help in the VPS +// consolidation; git.agentview.dev now dead-ends at a Traefik default +// cert + 404 (auditor had been failing listOpenPrs every cycle since +// Aug 25). Credentials come from ~/.git-credentials for HOST's domain, +// falling back to the user:pass embedded in this repo's origin remote. +// Basic auth works for both a PAT and a password on Gitea. +const HOST = process.env.GITEA_HOST ?? "https://git.warren.help"; const OWNER = "profit"; const REPO = "lakehouse"; const CRED_FILE = "/home/profit/.git-credentials"; +const GIT_CONFIG = "/home/profit/lakehouse/.git/config"; -let cachedPat: string | null = null; +let cachedAuth: string | null = null; -async function getPat(): Promise { - if (cachedPat) return cachedPat; - const raw = await readFile(CRED_FILE, "utf8"); - for (const line of raw.split("\n")) { - const m = line.match(/^https:\/\/[^:]+:([^@]+)@git\.agentview\.dev/); - if (m) { cachedPat = m[1]; return m[1]; } +async function getAuthHeader(): Promise { + if (cachedAuth) return cachedAuth; + const hostDomain = new URL(HOST).host.replace(/\./g, "\\."); + const credRe = new RegExp(`^https://([^:]+):([^@]+)@${hostDomain}`); + for (const file of [CRED_FILE, GIT_CONFIG]) { + let raw: string; + try { raw = await readFile(file, "utf8"); } catch { continue; } + for (const line of raw.split("\n")) { + const m = line.trim().replace(/^url = /, "").match(credRe); + if (m) { + cachedAuth = `Basic ${Buffer.from(`${decodeURIComponent(m[1])}:${decodeURIComponent(m[2])}`).toString("base64")}`; + return cachedAuth; + } + } } - throw new Error(`no Gitea PAT in ${CRED_FILE}`); + throw new Error(`no Gitea credentials for ${HOST} in ${CRED_FILE} or ${GIT_CONFIG}`); } async function giteaFetch(path: string, init: RequestInit = {}): Promise { - const pat = await getPat(); const url = `${HOST}/api/v1${path}`; const headers = new Headers(init.headers); - headers.set("Authorization", `token ${pat}`); + headers.set("Authorization", await getAuthHeader()); if (init.body && !headers.has("content-type")) { headers.set("content-type", "application/json"); }