From ee2b83cf838eaa442f79c58640e3d322b536d50f Mon Sep 17 00:00:00 2001 From: Coco Sheng Date: Tue, 10 Mar 2026 17:13:01 -0400 Subject: [PATCH 1/7] fix: resolve hang by prioritizing authentication and unsetting conflicting credentials --- action.yml | 68 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/action.yml b/action.yml index 54acd0f94..02b6f65ec 100644 --- a/action.yml +++ b/action.yml @@ -107,7 +107,7 @@ runs: id: 'validate_inputs' shell: 'bash' run: |- - set -exuo pipefail + set -euo pipefail # Emit a clear warning in three places without failing the step warn() { @@ -134,7 +134,7 @@ runs: fi if [[ ${auth_methods} -gt 1 ]]; then - warn "Multiple authentication methods provided. Please use only one of 'gemini_api_key', 'google_api_key', or 'gcp_workload_identity_provider'." + echo "::notice title=Authentication priority::Multiple authentication methods provided. The action will prioritize them in the following order: 1. Workload Identity Federation, 2. Vertex AI API Key, 3. Gemini API Key. Conflicting environment variables will be unset for the CLI." fi # Validate Workload Identity Federation inputs @@ -231,9 +231,14 @@ runs: GEMINI_CLI_VERSION: '${{ inputs.gemini_cli_version }}' EXTENSIONS: '${{ inputs.extensions }}' USE_PNPM: '${{ inputs.use_pnpm }}' + GOOGLE_CLOUD_ACCESS_TOKEN: '${{ steps.auth.outputs.access_token }}' + GOOGLE_GENAI_USE_VERTEXAI: '${{ inputs.use_vertex_ai }}' + GEMINI_API_KEY: '${{ inputs.gemini_api_key }}' + GOOGLE_API_KEY: '${{ inputs.google_api_key }}' shell: 'bash' run: |- set -euo pipefail + mkdir -p ~/.gemini VERSION_INPUT="${GEMINI_CLI_VERSION:-latest}" @@ -260,6 +265,20 @@ runs: echo "Error: Gemini CLI not found in PATH" exit 1 fi + + # Sanitize authentication environment variables to avoid conflicts when installing extensions. + if [[ -n "${GOOGLE_CLOUD_ACCESS_TOKEN:-}" ]]; then + unset GEMINI_API_KEY + unset GOOGLE_API_KEY + elif [[ "${GOOGLE_GENAI_USE_VERTEXAI:-false}" == "true" && -n "${GOOGLE_API_KEY:-}" ]]; then + unset GEMINI_API_KEY + elif [[ -n "${GEMINI_API_KEY:-}" ]]; then + export GOOGLE_GENAI_USE_VERTEXAI="false" + export GOOGLE_GENAI_USE_GCA="false" + unset GOOGLE_API_KEY + unset GOOGLE_CLOUD_ACCESS_TOKEN + fi + if [[ -n "${EXTENSIONS}" ]]; then echo "Installing Gemini CLI extensions:" echo "${EXTENSIONS}" | jq -r '.[]' | while IFS= read -r extension; do @@ -289,6 +308,26 @@ runs: # Keep track of whether we've failed FAILED=false + # Sanitize authentication environment variables to avoid conflicts. + # Priority: + # 1. Workload Identity Federation (use_vertex_ai or use_gemini_code_assist with access token) + # 2. Vertex AI API Key (use_vertex_ai with google_api_key) + # 3. Gemini API Key (gemini_api_key) + if [[ -n "${GOOGLE_CLOUD_ACCESS_TOKEN:-}" ]]; then + unset GEMINI_API_KEY + unset GOOGLE_API_KEY + # Unset credential file pointers that might cause conflicts with the access token and hang. + unset CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE + unset GOOGLE_GHA_CREDS_PATH + elif [[ "${GOOGLE_GENAI_USE_VERTEXAI:-false}" == "true" && -n "${GOOGLE_API_KEY:-}" ]]; then + unset GEMINI_API_KEY + elif [[ -n "${GEMINI_API_KEY:-}" ]]; then + export GOOGLE_GENAI_USE_VERTEXAI="false" + export GOOGLE_GENAI_USE_GCA="false" + unset GOOGLE_API_KEY + unset GOOGLE_CLOUD_ACCESS_TOKEN + fi + # Run Gemini CLI with the provided prompt, using JSON output format # We capture stdout (JSON) to TEMP_STDOUT and stderr to TEMP_STDERR if [[ "${GEMINI_DEBUG}" = true ]]; then @@ -324,12 +363,18 @@ runs: if jq -e . "${TEMP_STDOUT}" >/dev/null 2>&1; then RESPONSE=$(jq -r '.response // ""' "${TEMP_STDOUT}") fi - if jq -e . "${TEMP_STDERR}" >/dev/null 2>&1; then - ERROR_JSON=$(jq -c '.error // empty' "${TEMP_STDERR}") + + # Stderr might contain non-JSON (like stack traces), so we try to extract the last valid JSON object + if grep -q "{" "${TEMP_STDERR}"; then + # Extract the last curly-braced block from stderr + ERROR_CANDIDATE=$(tac "${TEMP_STDERR}" | awk '/^}/{p=1} p; /^{/{if(p)exit}' | tac) + if [[ -n "${ERROR_CANDIDATE}" ]] && jq -e . <<< "${ERROR_CANDIDATE}" >/dev/null 2>&1; then + ERROR_JSON=$(jq -c '.error // empty' <<< "${ERROR_CANDIDATE}") + fi fi - if { [[ -s "${TEMP_STDERR}" ]] && ! jq -e . "${TEMP_STDERR}" >/dev/null 2>&1; }; then - echo "::warning::Gemini CLI stderr was not valid JSON" + if { [[ -s "${TEMP_STDERR}" ]] && [[ -z "${ERROR_JSON}" ]]; }; then + echo "::warning::Gemini CLI stderr contains data but no valid JSON error object was extracted" fi if { [[ -s "${TEMP_STDOUT}" ]] && ! jq -e . "${TEMP_STDOUT}" >/dev/null 2>&1; }; then @@ -338,22 +383,25 @@ runs: # Set the captured response as a step output, supporting multiline - echo "gemini_response<> "${GITHUB_OUTPUT}" + # Use a unique delimiter to avoid collisions + EOF_DELIMITER="gh_gemini_out_$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)" + + echo "gemini_response<<${EOF_DELIMITER}" >> "${GITHUB_OUTPUT}" if [[ -n "${RESPONSE}" ]]; then echo "${RESPONSE}" >> "${GITHUB_OUTPUT}" else cat "${TEMP_STDOUT}" >> "${GITHUB_OUTPUT}" fi - echo "EOF" >> "${GITHUB_OUTPUT}" + echo "${EOF_DELIMITER}" >> "${GITHUB_OUTPUT}" # Set the captured errors as a step output, supporting multiline - echo "gemini_errors<> "${GITHUB_OUTPUT}" + echo "gemini_errors<<${EOF_DELIMITER}" >> "${GITHUB_OUTPUT}" if [[ -n "${ERROR_JSON}" ]]; then echo "${ERROR_JSON}" >> "${GITHUB_OUTPUT}" else cat "${TEMP_STDERR}" >> "${GITHUB_OUTPUT}" fi - echo "EOF" >> "${GITHUB_OUTPUT}" + echo "${EOF_DELIMITER}" >> "${GITHUB_OUTPUT}" # Generate Job Summary if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then From 50b6b5f767b7e528fe73efc3281a09ce6d4be89f Mon Sep 17 00:00:00 2001 From: Coco Sheng Date: Tue, 10 Mar 2026 17:19:43 -0400 Subject: [PATCH 2/7] fix: resolve hang by aggressively unsetting GOOGLE_APPLICATION_CREDENTIALS when access token is present --- action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/action.yml b/action.yml index 02b6f65ec..2cc204686 100644 --- a/action.yml +++ b/action.yml @@ -270,6 +270,7 @@ runs: if [[ -n "${GOOGLE_CLOUD_ACCESS_TOKEN:-}" ]]; then unset GEMINI_API_KEY unset GOOGLE_API_KEY + unset GOOGLE_APPLICATION_CREDENTIALS elif [[ "${GOOGLE_GENAI_USE_VERTEXAI:-false}" == "true" && -n "${GOOGLE_API_KEY:-}" ]]; then unset GEMINI_API_KEY elif [[ -n "${GEMINI_API_KEY:-}" ]]; then @@ -317,6 +318,7 @@ runs: unset GEMINI_API_KEY unset GOOGLE_API_KEY # Unset credential file pointers that might cause conflicts with the access token and hang. + unset GOOGLE_APPLICATION_CREDENTIALS unset CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE unset GOOGLE_GHA_CREDS_PATH elif [[ "${GOOGLE_GENAI_USE_VERTEXAI:-false}" == "true" && -n "${GOOGLE_API_KEY:-}" ]]; then From 751b609456cce5b11326948bbed9399e2653af8b Mon Sep 17 00:00:00 2001 From: Coco Sheng Date: Tue, 10 Mar 2026 17:22:28 -0400 Subject: [PATCH 3/7] test: use local action in workflows for PR verification --- .github/workflows/gemini-invoke.yml | 2 +- .github/workflows/gemini-issue-fixer.yml | 2 +- .github/workflows/gemini-plan-execute.yml | 2 +- .github/workflows/gemini-review.yml | 2 +- .github/workflows/gemini-scheduled-triage.yml | 2 +- .github/workflows/gemini-triage.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/gemini-invoke.yml b/.github/workflows/gemini-invoke.yml index 5bec70a52..a308ae184 100644 --- a/.github/workflows/gemini-invoke.yml +++ b/.github/workflows/gemini-invoke.yml @@ -42,7 +42,7 @@ jobs: - name: 'Run Gemini CLI' id: 'run_gemini' - uses: 'google-github-actions/run-gemini-cli@main' # ratchet:exclude + uses: './' # ratchet:exclude env: TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}' DESCRIPTION: '${{ github.event.pull_request.body || github.event.issue.body }}' diff --git a/.github/workflows/gemini-issue-fixer.yml b/.github/workflows/gemini-issue-fixer.yml index a19804418..1a72ebedb 100644 --- a/.github/workflows/gemini-issue-fixer.yml +++ b/.github/workflows/gemini-issue-fixer.yml @@ -39,7 +39,7 @@ jobs: uses: 'actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8' # ratchet:actions/checkout@v6 - name: 'Run Gemini PR Create' - uses: 'google-github-actions/run-gemini-cli@main' # ratchet:exclude + uses: './' # ratchet:exclude id: 'gemini_pr_create' env: GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN }}' diff --git a/.github/workflows/gemini-plan-execute.yml b/.github/workflows/gemini-plan-execute.yml index 9dfe61a21..56ce7dd86 100644 --- a/.github/workflows/gemini-plan-execute.yml +++ b/.github/workflows/gemini-plan-execute.yml @@ -44,7 +44,7 @@ jobs: - name: 'Run Gemini CLI' id: 'run_gemini' - uses: 'google-github-actions/run-gemini-cli@main' # ratchet:exclude + uses: './' # ratchet:exclude env: TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}' DESCRIPTION: '${{ github.event.pull_request.body || github.event.issue.body }}' diff --git a/.github/workflows/gemini-review.yml b/.github/workflows/gemini-review.yml index dc525cd74..6d17d5d02 100644 --- a/.github/workflows/gemini-review.yml +++ b/.github/workflows/gemini-review.yml @@ -42,7 +42,7 @@ jobs: uses: 'actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8' # ratchet:actions/checkout@v6 - name: 'Run Gemini pull request review' - uses: 'google-github-actions/run-gemini-cli@main' # ratchet:exclude + uses: './' # ratchet:exclude id: 'gemini_pr_review' env: GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}' diff --git a/.github/workflows/gemini-scheduled-triage.yml b/.github/workflows/gemini-scheduled-triage.yml index 962164576..c21789488 100644 --- a/.github/workflows/gemini-scheduled-triage.yml +++ b/.github/workflows/gemini-scheduled-triage.yml @@ -89,7 +89,7 @@ jobs: id: 'gemini_issue_analysis' if: |- ${{ steps.find_issues.outputs.issues_to_triage != '[]' }} - uses: 'google-github-actions/run-gemini-cli@main' # ratchet:exclude + uses: './' # ratchet:exclude env: GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs ISSUES_TO_TRIAGE: '${{ steps.find_issues.outputs.issues_to_triage }}' diff --git a/.github/workflows/gemini-triage.yml b/.github/workflows/gemini-triage.yml index 22b1413c2..a298164b8 100644 --- a/.github/workflows/gemini-triage.yml +++ b/.github/workflows/gemini-triage.yml @@ -59,7 +59,7 @@ jobs: id: 'gemini_analysis' if: |- ${{ steps.get_labels.outputs.available_labels != '' }} - uses: 'google-github-actions/run-gemini-cli@main' # ratchet:exclude + uses: './' # ratchet:exclude env: GITHUB_TOKEN: '' # Do NOT pass any auth tokens here since this runs on untrusted inputs ISSUE_TITLE: '${{ github.event.issue.title }}' From eba38aea5c07dbaab535fa51e98bac5af41cbfe0 Mon Sep 17 00:00:00 2001 From: Coco Sheng Date: Tue, 10 Mar 2026 17:34:27 -0400 Subject: [PATCH 4/7] test: add minimal workflow to debug hang --- .github/workflows/test-minimal.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/test-minimal.yml diff --git a/.github/workflows/test-minimal.yml b/.github/workflows/test-minimal.yml new file mode 100644 index 000000000..f5a47ada5 --- /dev/null +++ b/.github/workflows/test-minimal.yml @@ -0,0 +1,21 @@ +name: '🧪 Test Minimal' +on: + workflow_dispatch: + push: + branches: + - 'fix/auth-priority-and-hang' + paths: + - '.github/workflows/test-minimal.yml' + +jobs: + test: + runs-on: 'ubuntu-latest' + steps: + - name: 'Checkout' + uses: 'actions/checkout@v4' + + - name: 'Run Gemini Version' + uses: './' + with: + prompt: '--version' + gemini_debug: true From 98d258f9cd459d6b20c01214eb542d77cf98e32c Mon Sep 17 00:00:00 2001 From: Coco Sheng Date: Tue, 10 Mar 2026 17:39:06 -0400 Subject: [PATCH 5/7] fix: aggressively unset GOOGLE_APPLICATION_CREDENTIALS to prevent hang --- action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/action.yml b/action.yml index 2cc204686..d6dd630ab 100644 --- a/action.yml +++ b/action.yml @@ -309,6 +309,10 @@ runs: # Keep track of whether we've failed FAILED=false + # Always unset GOOGLE_APPLICATION_CREDENTIALS to prevent the CLI from hanging on credential discovery + # in environments where multiple auth methods might be present (like GHA). + unset GOOGLE_APPLICATION_CREDENTIALS + # Sanitize authentication environment variables to avoid conflicts. # Priority: # 1. Workload Identity Federation (use_vertex_ai or use_gemini_code_assist with access token) From a57ae1576624f5117eaae7ea7d066cf46c12403f Mon Sep 17 00:00:00 2001 From: Coco Sheng Date: Tue, 10 Mar 2026 17:39:35 -0400 Subject: [PATCH 6/7] force trigger test From 0768ef5bad177463c11c7d1a2f5dc67ea2e2e6eb Mon Sep 17 00:00:00 2001 From: Coco Sheng Date: Tue, 10 Mar 2026 17:40:08 -0400 Subject: [PATCH 7/7] force trigger test 2