From 9ce4dbf015181e6dc6803d0676c942e853cc5e2d Mon Sep 17 00:00:00 2001 From: alpha nerd Date: Tue, 2 Jun 2026 08:34:31 +0200 Subject: [PATCH] fix: correctly check permissions --- index.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/index.ts b/index.ts index c495df3..88be5bc 100644 --- a/index.ts +++ b/index.ts @@ -665,11 +665,15 @@ async function assertPermissions() { return } - // Otherwise the actor must have write access, i.e. be a collaborator/member. - // Forgejo: GET .../collaborators/{user} returns 204 if a collaborator, 404 if not. - // We use a raw fetch (not forgejoFetch) because the 204 response has no JSON body. + // Otherwise the actor must have at least write access. We query the effective + // permission endpoint rather than the bare collaborators endpoint, because the + // latter only lists *direct* collaborators and 404s for users who inherit + // access through an organization team (e.g. the "owners" team). + // Forgejo: GET .../collaborators/{user}/permission returns + // { permission: "admin" | "write" | "read" | "none", ... } + // accounting for direct collaboration, team membership, and org ownership. const { forgejoToken } = getForgejoConfig() - const url = forgejoApiUrl("repos", context.repo.owner, context.repo.repo, "collaborators", actor) + const url = forgejoApiUrl("repos", context.repo.owner, context.repo.repo, "collaborators", actor, "permission") let res: Response try { res = await fetch(url, { headers: { Authorization: `token ${forgejoToken}` } }) @@ -678,9 +682,16 @@ async function assertPermissions() { throw new Error(`Could not verify permissions for "${actor}": ${error.message}`) } - if (res.status === 204 || res.ok) { - console.log(" permission: write (collaborator)") - return + if (res.ok) { + const { permission } = (await res.json().catch(() => ({}))) as { permission?: string } + if (permission === "admin" || permission === "write") { + console.log(` permission: ${permission}`) + return + } + throw new Error( + `User "${actor}" is not authorized to trigger this action ` + + `(requires write access to ${context.repo.owner}/${context.repo.repo}, has "${permission ?? "none"}").`, + ) } if (res.status === 404) { throw new Error(