fix(repos): a scoped connection can name a user, not just an org
deploy / test (push) Successful in 4m19s
deploy / build (push) Successful in 5m42s

Scoping a Gitea connection to `osobh` — the personal namespace clawmates itself
lives in — failed with "org 'osobh' not found or PAT lacks access". The sync
only ever called /orgs/{owner}/repos, and Gitea serves user namespaces from
/users/{owner}/repos. The error pointed at permissions for what was really a
wrong endpoint, which is the kind of message that sends you to rotate a token
that was fine.

Retry as a user on 404 before giving up, and say what was actually checked.

Verified: owner=osobh now syncs 7 repos, owner=redclaw 22 — 29 instead of the
182 an unscoped connection pulls.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-08-14 21:00:17 -07:00
co-authored by Claude Opus 5
parent b290025fc4
commit 8ef7067467
+19 -2
View File
@@ -430,13 +430,30 @@ async fn sync_gitea(
Some(owner) => format!("{api_base}/orgs/{owner}/repos?limit={per_page}&page={page}"),
None => format!("{api_base}/repos/search?limit={per_page}&page={page}"),
};
let (status, body) = broker
let (mut status, mut body) = broker
.fetch_authorized(secret_ref, &url)
.await
.map_err(|e| format!("broker fetch: {e}"))?;
// A Gitea owner is either an ORG or a USER, and they live on different
// endpoints. Scoping a connection to a personal namespace — `osobh`,
// where clawmates itself lives — 404s on /orgs and reported "not found
// or PAT lacks access", which points at permissions when the account is
// simply not an org. Retry as a user before giving up.
if status == 404 {
if let Some(owner) = conn.owner.as_deref() {
let user_url =
format!("{api_base}/users/{owner}/repos?limit={per_page}&page={page}");
let (s2, b2) = broker
.fetch_authorized(secret_ref, &user_url)
.await
.map_err(|e| format!("broker fetch: {e}"))?;
status = s2;
body = b2;
}
}
if status == 404 && conn.owner.is_some() {
return Err(format!(
"org '{}' not found or PAT lacks access",
"'{}' matched neither an org nor a user, or the PAT lacks access",
conn.owner.as_deref().unwrap_or("")
));
}