From 864688a371d8b298b73fe46aa2d464d936a21c0f Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 20 Oct 2026 16:09:31 +0000 Subject: [PATCH] fix(coder/github-upload-public-key): follow pagination when checking existing keys GitHub returns 30 keys per page by default, so a Coder key on a later page was missed and uploaded again. Request 100 keys per page and keep fetching until the key is found or a short page is returned. --- .../github-upload-public-key/main.test.ts | 30 ++++++++++ .../modules/github-upload-public-key/run.sh | 57 +++++++++++-------- 2 files changed, 62 insertions(+), 25 deletions(-) diff --git a/registry/coder/modules/github-upload-public-key/main.test.ts b/registry/coder/modules/github-upload-public-key/main.test.ts index 692ec6989..c5193b440 100644 --- a/registry/coder/modules/github-upload-public-key/main.test.ts +++ b/registry/coder/modules/github-upload-public-key/main.test.ts @@ -113,6 +113,19 @@ const setupServer = () => { ]); } + // case: key exists on the second page + if (req.headers.get("Authorization") === "Bearer paginated") { + const perPage = Number(url.searchParams.get("per_page") ?? 30); + const page = Number(url.searchParams.get("page") ?? 1); + const keys = [ + ...Array.from({ length: perPage }, (_, i) => ({ key: `foo-${i}` })), + { key: "exists" }, + ]; + return createJSONResponse( + keys.slice((page - 1) * perPage, page * perPage), + ); + } + // case: key does not exist return createJSONResponse([ { @@ -238,6 +251,23 @@ describe("github-upload-public-key", () => { ]); }); + it("finds an existing key on a later page", async () => { + const { id, run, uploads } = await setupContainer(undefined, { + key_type: "both", + }); + await writeCoder(id, "echo paginated"); + + const exec = await run(); + expect(exec.stdout).toContain( + "Your Coder public key is already a GitHub authentication key!", + ); + expect(exec.stdout).toContain( + "Your Coder public key is already a GitHub signing key!", + ); + expect(exec.exitCode).toBe(0); + expect(uploads).toEqual([]); + }); + it("skips existing keys when key_type is both", async () => { const { id, run, uploads } = await setupContainer(undefined, { key_type: "both", diff --git a/registry/coder/modules/github-upload-public-key/run.sh b/registry/coder/modules/github-upload-public-key/run.sh index 1813895d6..58f816d49 100644 --- a/registry/coder/modules/github-upload-public-key/run.sh +++ b/registry/coder/modules/github-upload-public-key/run.sh @@ -69,31 +69,38 @@ upload_key() { local label="$2" echo "Fetching $label keys from GitHub..." - local keys_response - keys_response=$( - curl -L -s \ - -w "\n%%{http_code}" \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $GITHUB_TOKEN" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "$GITHUB_API_URL/user/$endpoint" - ) - local keys_status keys_body - keys_status=$(tail -n1 <<< "$keys_response") - keys_body=$(sed \$d <<< "$keys_response") - - if [ "$keys_status" -ne 200 ]; then - echo "Failed to fetch GitHub $label keys with status code $keys_status!" - echo "$keys_body" - return 1 - fi - - local match - match=$(jq -r --arg PUBLIC_KEY "$PUBLIC_KEY" '.[] | select(.key == $PUBLIC_KEY) | .key' <<< "$keys_body") - if [ "$PUBLIC_KEY" = "$match" ]; then - echo "Your Coder public key is already a GitHub $label key!" - return 0 - fi + local per_page=100 page=1 + local keys_response keys_status keys_body match count + while true; do + keys_response=$( + curl -L -s \ + -w "\n%%{http_code}" \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "$GITHUB_API_URL/user/$endpoint?per_page=$per_page&page=$page" + ) + keys_status=$(tail -n1 <<< "$keys_response") + keys_body=$(sed \$d <<< "$keys_response") + + if [ "$keys_status" -ne 200 ]; then + echo "Failed to fetch GitHub $label keys with status code $keys_status!" + echo "$keys_body" + return 1 + fi + + match=$(jq -r --arg PUBLIC_KEY "$PUBLIC_KEY" '.[] | select(.key == $PUBLIC_KEY) | .key' <<< "$keys_body") + if [ "$PUBLIC_KEY" = "$match" ]; then + echo "Your Coder public key is already a GitHub $label key!" + return 0 + fi + + count=$(jq 'length' <<< "$keys_body") + if [ "$count" -lt "$per_page" ]; then + break + fi + page=$((page + 1)) + done echo "Your Coder public key is not a GitHub $label key yet. Adding it now..." local upload_response