From 231bd75b7196d48291c1498f1c6d277c2810d9a3 Mon Sep 17 00:00:00 2001 From: Ashwin Bhat Date: Mon, 26 Jan 2026 21:40:04 -0800 Subject: [PATCH] Revert "feat: send additional_permissions in token exchange request (#859)" (#864) This reverts commit 0c704179b5caf6267b7002268193a23bb73652e3. --- docs/configuration.md | 9 +--- src/github/token.ts | 63 +++------------------- test/parse-permissions.test.ts | 97 ---------------------------------- 3 files changed, 10 insertions(+), 159 deletions(-) delete mode 100644 test/parse-permissions.test.ts diff --git a/docs/configuration.md b/docs/configuration.md index eb352b34..46c2687c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -172,14 +172,9 @@ jobs: **Important Notes**: -- The GitHub token must have the corresponding permission in your workflow +- The GitHub token must have the `actions: read` permission in your workflow - If the permission is missing, Claude will warn you and suggest adding it -- The following additional permissions can be requested beyond the defaults: - - `actions: read` - - `checks: read` - - `discussions: read` or `discussions: write` - - `workflows: read` or `workflows: write` -- Standard permissions (`contents: write`, `pull_requests: write`, `issues: write`) are always included and do not need to be specified +- Currently, only `actions: read` is supported, but the format allows for future extensions ## Custom Environment Variables diff --git a/src/github/token.ts b/src/github/token.ts index 54948d19..6cb9079c 100644 --- a/src/github/token.ts +++ b/src/github/token.ts @@ -16,60 +16,15 @@ async function getOidcToken(): Promise { } } -const DEFAULT_PERMISSIONS: Record = { - contents: "write", - pull_requests: "write", - issues: "write", -}; - -export function parseAdditionalPermissions(): - | Record - | undefined { - const raw = process.env.ADDITIONAL_PERMISSIONS; - if (!raw || !raw.trim()) { - return undefined; - } - - const additional: Record = {}; - for (const line of raw.split("\n")) { - const trimmed = line.trim(); - if (!trimmed) continue; - const colonIndex = trimmed.indexOf(":"); - if (colonIndex === -1) continue; - const key = trimmed.slice(0, colonIndex).trim(); - const value = trimmed.slice(colonIndex + 1).trim(); - if (key && value) { - additional[key] = value; - } - } - - if (Object.keys(additional).length === 0) { - return undefined; - } - - return { ...DEFAULT_PERMISSIONS, ...additional }; -} - -async function exchangeForAppToken( - oidcToken: string, - permissions?: Record, -): Promise { - const headers: Record = { - Authorization: `Bearer ${oidcToken}`, - }; - const fetchOptions: RequestInit = { - method: "POST", - headers, - }; - - if (permissions) { - headers["Content-Type"] = "application/json"; - fetchOptions.body = JSON.stringify({ permissions }); - } - +async function exchangeForAppToken(oidcToken: string): Promise { const response = await fetch( "https://api.anthropic.com/api/github/github-app-token-exchange", - fetchOptions, + { + method: "POST", + headers: { + Authorization: `Bearer ${oidcToken}`, + }, + }, ); if (!response.ok) { @@ -134,11 +89,9 @@ export async function setupGitHubToken(): Promise { const oidcToken = await retryWithBackoff(() => getOidcToken()); console.log("OIDC token successfully obtained"); - const permissions = parseAdditionalPermissions(); - console.log("Exchanging OIDC token for app token..."); const appToken = await retryWithBackoff(() => - exchangeForAppToken(oidcToken, permissions), + exchangeForAppToken(oidcToken), ); console.log("App token successfully obtained"); diff --git a/test/parse-permissions.test.ts b/test/parse-permissions.test.ts deleted file mode 100644 index a13f9234..00000000 --- a/test/parse-permissions.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { describe, expect, test, beforeEach, afterEach } from "bun:test"; -import { parseAdditionalPermissions } from "../src/github/token"; - -describe("parseAdditionalPermissions", () => { - let originalEnv: string | undefined; - - beforeEach(() => { - originalEnv = process.env.ADDITIONAL_PERMISSIONS; - }); - - afterEach(() => { - if (originalEnv === undefined) { - delete process.env.ADDITIONAL_PERMISSIONS; - } else { - process.env.ADDITIONAL_PERMISSIONS = originalEnv; - } - }); - - test("returns undefined when env var is not set", () => { - delete process.env.ADDITIONAL_PERMISSIONS; - expect(parseAdditionalPermissions()).toBeUndefined(); - }); - - test("returns undefined when env var is empty string", () => { - process.env.ADDITIONAL_PERMISSIONS = ""; - expect(parseAdditionalPermissions()).toBeUndefined(); - }); - - test("returns undefined when env var is only whitespace", () => { - process.env.ADDITIONAL_PERMISSIONS = " \n \n "; - expect(parseAdditionalPermissions()).toBeUndefined(); - }); - - test("parses single permission and merges with defaults", () => { - process.env.ADDITIONAL_PERMISSIONS = "actions: read"; - expect(parseAdditionalPermissions()).toEqual({ - contents: "write", - pull_requests: "write", - issues: "write", - actions: "read", - }); - }); - - test("parses multiple permissions", () => { - process.env.ADDITIONAL_PERMISSIONS = "actions: read\nworkflows: write"; - expect(parseAdditionalPermissions()).toEqual({ - contents: "write", - pull_requests: "write", - issues: "write", - actions: "read", - workflows: "write", - }); - }); - - test("additional permissions can override defaults", () => { - process.env.ADDITIONAL_PERMISSIONS = "contents: read"; - expect(parseAdditionalPermissions()).toEqual({ - contents: "read", - pull_requests: "write", - issues: "write", - }); - }); - - test("handles extra whitespace around keys and values", () => { - process.env.ADDITIONAL_PERMISSIONS = " actions : read "; - expect(parseAdditionalPermissions()).toEqual({ - contents: "write", - pull_requests: "write", - issues: "write", - actions: "read", - }); - }); - - test("skips empty lines", () => { - process.env.ADDITIONAL_PERMISSIONS = - "actions: read\n\n\nworkflows: write\n\n"; - expect(parseAdditionalPermissions()).toEqual({ - contents: "write", - pull_requests: "write", - issues: "write", - actions: "read", - workflows: "write", - }); - }); - - test("skips lines without colons", () => { - process.env.ADDITIONAL_PERMISSIONS = - "actions: read\ninvalid line\nworkflows: write"; - expect(parseAdditionalPermissions()).toEqual({ - contents: "write", - pull_requests: "write", - issues: "write", - actions: "read", - workflows: "write", - }); - }); -});