@@ -107,7 +107,7 @@ runs:
107107 id : ' validate_inputs'
108108 shell : ' bash'
109109 run : |-
110- set -exuo pipefail
110+ set -euo pipefail
111111
112112 # Emit a clear warning in three places without failing the step
113113 warn() {
@@ -134,7 +134,7 @@ runs:
134134 fi
135135
136136 if [[ ${auth_methods} -gt 1 ]]; then
137- warn " Multiple authentication methods provided. Please use only one of 'gemini_api_key', 'google_api_key', or 'gcp_workload_identity_provider' ."
137+ 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 ."
138138 fi
139139
140140 # Validate Workload Identity Federation inputs
@@ -231,9 +231,14 @@ runs:
231231 GEMINI_CLI_VERSION : ' ${{ inputs.gemini_cli_version }}'
232232 EXTENSIONS : ' ${{ inputs.extensions }}'
233233 USE_PNPM : ' ${{ inputs.use_pnpm }}'
234+ GOOGLE_CLOUD_ACCESS_TOKEN : ' ${{ steps.auth.outputs.access_token }}'
235+ GOOGLE_GENAI_USE_VERTEXAI : ' ${{ inputs.use_vertex_ai }}'
236+ GEMINI_API_KEY : ' ${{ inputs.gemini_api_key }}'
237+ GOOGLE_API_KEY : ' ${{ inputs.google_api_key }}'
234238 shell : ' bash'
235239 run : |-
236240 set -euo pipefail
241+ mkdir -p ~/.gemini
237242
238243 VERSION_INPUT="${GEMINI_CLI_VERSION:-latest}"
239244
@@ -260,6 +265,20 @@ runs:
260265 echo "Error: Gemini CLI not found in PATH"
261266 exit 1
262267 fi
268+
269+ # Sanitize authentication environment variables to avoid conflicts when installing extensions.
270+ if [[ -n "${GOOGLE_CLOUD_ACCESS_TOKEN:-}" ]]; then
271+ unset GEMINI_API_KEY
272+ unset GOOGLE_API_KEY
273+ elif [[ "${GOOGLE_GENAI_USE_VERTEXAI:-false}" == "true" && -n "${GOOGLE_API_KEY:-}" ]]; then
274+ unset GEMINI_API_KEY
275+ elif [[ -n "${GEMINI_API_KEY:-}" ]]; then
276+ export GOOGLE_GENAI_USE_VERTEXAI="false"
277+ export GOOGLE_GENAI_USE_GCA="false"
278+ unset GOOGLE_API_KEY
279+ unset GOOGLE_CLOUD_ACCESS_TOKEN
280+ fi
281+
263282 if [[ -n "${EXTENSIONS}" ]]; then
264283 echo "Installing Gemini CLI extensions:"
265284 echo "${EXTENSIONS}" | jq -r '.[]' | while IFS= read -r extension; do
@@ -289,6 +308,26 @@ runs:
289308 # Keep track of whether we've failed
290309 FAILED=false
291310
311+ # Sanitize authentication environment variables to avoid conflicts.
312+ # Priority:
313+ # 1. Workload Identity Federation (use_vertex_ai or use_gemini_code_assist with access token)
314+ # 2. Vertex AI API Key (use_vertex_ai with google_api_key)
315+ # 3. Gemini API Key (gemini_api_key)
316+ if [[ -n "${GOOGLE_CLOUD_ACCESS_TOKEN:-}" ]]; then
317+ unset GEMINI_API_KEY
318+ unset GOOGLE_API_KEY
319+ # Unset credential file pointers that might cause conflicts with the access token and hang.
320+ unset CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE
321+ unset GOOGLE_GHA_CREDS_PATH
322+ elif [[ "${GOOGLE_GENAI_USE_VERTEXAI:-false}" == "true" && -n "${GOOGLE_API_KEY:-}" ]]; then
323+ unset GEMINI_API_KEY
324+ elif [[ -n "${GEMINI_API_KEY:-}" ]]; then
325+ export GOOGLE_GENAI_USE_VERTEXAI="false"
326+ export GOOGLE_GENAI_USE_GCA="false"
327+ unset GOOGLE_API_KEY
328+ unset GOOGLE_CLOUD_ACCESS_TOKEN
329+ fi
330+
292331 # Run Gemini CLI with the provided prompt, using JSON output format
293332 # We capture stdout (JSON) to TEMP_STDOUT and stderr to TEMP_STDERR
294333 if [[ "${GEMINI_DEBUG}" = true ]]; then
@@ -324,12 +363,18 @@ runs:
324363 if jq -e . "${TEMP_STDOUT}" >/dev/null 2>&1; then
325364 RESPONSE=$(jq -r '.response // ""' "${TEMP_STDOUT}")
326365 fi
327- if jq -e . "${TEMP_STDERR}" >/dev/null 2>&1; then
328- ERROR_JSON=$(jq -c '.error // empty' "${TEMP_STDERR}")
366+
367+ # Stderr might contain non-JSON (like stack traces), so we try to extract the last valid JSON object
368+ if grep -q "{" "${TEMP_STDERR}"; then
369+ # Extract the last curly-braced block from stderr
370+ ERROR_CANDIDATE=$(tac "${TEMP_STDERR}" | awk '/^}/{p=1} p; /^{/{if(p)exit}' | tac)
371+ if [[ -n "${ERROR_CANDIDATE}" ]] && jq -e . <<< "${ERROR_CANDIDATE}" >/dev/null 2>&1; then
372+ ERROR_JSON=$(jq -c '.error // empty' <<< "${ERROR_CANDIDATE}")
373+ fi
329374 fi
330375
331- if { [[ -s "${TEMP_STDERR}" ]] && ! jq -e . "${TEMP_STDERR }" >/dev/null 2>&1 ; }; then
332- echo "::warning::Gemini CLI stderr was not valid JSON"
376+ if { [[ -s "${TEMP_STDERR}" ]] && [[ -z "${ERROR_JSON }" ]] ; }; then
377+ echo "::warning::Gemini CLI stderr contains data but no valid JSON error object was extracted "
333378 fi
334379
335380 if { [[ -s "${TEMP_STDOUT}" ]] && ! jq -e . "${TEMP_STDOUT}" >/dev/null 2>&1; }; then
@@ -338,22 +383,25 @@ runs:
338383
339384
340385 # Set the captured response as a step output, supporting multiline
341- echo "gemini_response<<EOF" >> "${GITHUB_OUTPUT}"
386+ # Use a unique delimiter to avoid collisions
387+ EOF_DELIMITER="gh_gemini_out_$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)"
388+
389+ echo "gemini_response<<${EOF_DELIMITER}" >> "${GITHUB_OUTPUT}"
342390 if [[ -n "${RESPONSE}" ]]; then
343391 echo "${RESPONSE}" >> "${GITHUB_OUTPUT}"
344392 else
345393 cat "${TEMP_STDOUT}" >> "${GITHUB_OUTPUT}"
346394 fi
347- echo "EOF " >> "${GITHUB_OUTPUT}"
395+ echo "${EOF_DELIMITER} " >> "${GITHUB_OUTPUT}"
348396
349397 # Set the captured errors as a step output, supporting multiline
350- echo "gemini_errors<<EOF " >> "${GITHUB_OUTPUT}"
398+ echo "gemini_errors<<${EOF_DELIMITER} " >> "${GITHUB_OUTPUT}"
351399 if [[ -n "${ERROR_JSON}" ]]; then
352400 echo "${ERROR_JSON}" >> "${GITHUB_OUTPUT}"
353401 else
354402 cat "${TEMP_STDERR}" >> "${GITHUB_OUTPUT}"
355403 fi
356- echo "EOF " >> "${GITHUB_OUTPUT}"
404+ echo "${EOF_DELIMITER} " >> "${GITHUB_OUTPUT}"
357405
358406 # Generate Job Summary
359407 if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then
0 commit comments