fix: fail-close permission gate
This commit is contained in:
parent
9e1e054f05
commit
b4d8fd75d2
1 changed files with 37 additions and 19 deletions
56
index.ts
56
index.ts
|
|
@ -196,8 +196,10 @@ async function createAuthConfig(): Promise<string> {
|
|||
try {
|
||||
await createAuthConfig()
|
||||
|
||||
// Strip Forgejo write credentials from opencode's env so its bash tool cannot reach them.
|
||||
const STRIP_FROM_AGENT_ENV = new Set(["FORGEJO_TOKEN", "FORGEJO_PUSH_TOKEN", "GITHUB_TOKEN"])
|
||||
// Strip credentials from opencode's env so its bash tool cannot reach them.
|
||||
// NOMYO_API_KEY is handed to the server via OPENCODE_AUTH_CONTENT, so the raw
|
||||
// env var is not needed by the agent and is removed to limit exfiltration.
|
||||
const STRIP_FROM_AGENT_ENV = new Set(["FORGEJO_TOKEN", "FORGEJO_PUSH_TOKEN", "GITHUB_TOKEN", "NOMYO_API_KEY"])
|
||||
const agentEnv: NodeJS.ProcessEnv = {}
|
||||
for (const [k, v] of Object.entries(process.env)) {
|
||||
if (!STRIP_FROM_AGENT_ENV.has(k)) agentEnv[k] = v
|
||||
|
|
@ -216,9 +218,11 @@ try {
|
|||
forgejoHost = new URL(forgejoApiUrl).hostname
|
||||
accessToken = forgejoToken
|
||||
|
||||
// Gate on permissions before doing any work (fetching prompt images, etc.).
|
||||
await assertPermissions()
|
||||
|
||||
const { userPrompt, promptFiles } = await getUserPrompt()
|
||||
await configureGitIdentity()
|
||||
await assertPermissions()
|
||||
|
||||
const comment = await createComment()
|
||||
commentId = comment.id
|
||||
|
|
@ -655,23 +659,37 @@ async function assertPermissions() {
|
|||
|
||||
console.log(`Asserting permissions for user ${actor}...`)
|
||||
|
||||
try {
|
||||
// Forgejo: check if user is a collaborator/member
|
||||
await forgejoFetch<any>(
|
||||
forgejoApiUrl("repos", context.repo.owner, context.repo.repo, "collaborators", actor),
|
||||
)
|
||||
console.log(" permission: write (collaborator)")
|
||||
} catch (error: any) {
|
||||
// If not a collaborator, check if actor is the repo owner (via GITHUB_ACTOR)
|
||||
if (actor === context.repo.owner || actor === `${context.repo.owner}[bot]`) {
|
||||
console.log(" permission: admin (owner)")
|
||||
return
|
||||
}
|
||||
console.error(`Failed to check permissions: ${error.message}`)
|
||||
// In Actions context, if we can write to the repo, we have write access
|
||||
// We'll assume write access since the workflow has the right permissions
|
||||
console.log(" permission: write (assumed from workflow permissions)")
|
||||
// The repo owner (and its bot account) is always allowed.
|
||||
if (actor === context.repo.owner || actor === `${context.repo.owner}[bot]`) {
|
||||
console.log(" permission: admin (owner)")
|
||||
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.
|
||||
const { forgejoToken } = getForgejoConfig()
|
||||
const url = forgejoApiUrl("repos", context.repo.owner, context.repo.repo, "collaborators", actor)
|
||||
let res: Response
|
||||
try {
|
||||
res = await fetch(url, { headers: { Authorization: `token ${forgejoToken}` } })
|
||||
} catch (error: any) {
|
||||
// Fail closed: if we cannot verify permissions, deny.
|
||||
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.status === 404) {
|
||||
throw new Error(
|
||||
`User "${actor}" is not authorized to trigger this action ` +
|
||||
`(requires write access to ${context.repo.owner}/${context.repo.repo}).`,
|
||||
)
|
||||
}
|
||||
const text = await res.text().catch(() => "")
|
||||
throw new Error(`Could not verify permissions for "${actor}": ${res.status} ${res.statusText} ${text}`)
|
||||
}
|
||||
|
||||
// ─── Git operations ─────────────────────────────────────────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue