chore(ci): Ensure action and community workflows are consistent and not vulnerable to injection attacks (#6107)

This commit is contained in:
Seth Vargo 2025-08-12 22:36:37 -04:00 committed by GitHub
parent 0e8bbfb8ba
commit b6da98e8e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 136 additions and 122 deletions

View File

@ -27,79 +27,88 @@ inputs:
runs: runs:
using: 'composite' using: 'composite'
steps: steps:
- name: Prepare Coverage Comment - name: 'Prepare Coverage Comment'
id: prep_coverage_comment id: 'prep_coverage_comment'
shell: bash shell: 'bash'
run: | env:
cli_json_file="${{ inputs.cli_json_file }}" CLI_JSON_FILE: '${{ inputs.cli_json_file }}'
core_json_file="${{ inputs.core_json_file }}" CORE_JSON_FILE: '${{ inputs.core_json_file }}'
cli_full_text_summary_file="${{ inputs.cli_full_text_summary_file }}" CLI_FULL_TEXT_SUMMARY_FILE: '${{ inputs.cli_full_text_summary_file }}'
core_full_text_summary_file="${{ inputs.core_full_text_summary_file }}" CORE_FULL_TEXT_SUMMARY_FILE: '${{ inputs.core_full_text_summary_file }}'
comment_file="coverage-comment.md" COMMENT_FILE: 'coverage-comment.md'
NODE_VERSION: '${{ inputs.node_version }}'
OS: '${{ inputs.os }}'
run: |-
# Extract percentages using jq for the main table # Extract percentages using jq for the main table
if [ -f "$cli_json_file" ]; then if [ -f "${CLI_JSON_FILE}" ]; then
cli_lines_pct=$(jq -r '.total.lines.pct' "$cli_json_file") cli_lines_pct="$(jq -r '.total.lines.pct' "${CLI_JSON_FILE}")"
cli_statements_pct=$(jq -r '.total.statements.pct' "$cli_json_file") cli_statements_pct="$(jq -r '.total.statements.pct' "${CLI_JSON_FILE}")"
cli_functions_pct=$(jq -r '.total.functions.pct' "$cli_json_file") cli_functions_pct="$(jq -r '.total.functions.pct' "${CLI_JSON_FILE}")"
cli_branches_pct=$(jq -r '.total.branches.pct' "$cli_json_file") cli_branches_pct="$(jq -r '.total.branches.pct' "${CLI_JSON_FILE}")"
else else
cli_lines_pct="N/A"; cli_statements_pct="N/A"; cli_functions_pct="N/A"; cli_branches_pct="N/A" cli_lines_pct="N/A"
echo "CLI coverage-summary.json not found at: $cli_json_file" >&2 # Error to stderr cli_statements_pct="N/A"
cli_functions_pct="N/A"
cli_branches_pct="N/A"
echo "CLI coverage-summary.json not found at: ${CLI_JSON_FILE}" >&2 # Error to stderr
fi fi
if [ -f "$core_json_file" ]; then if [ -f "${CORE_JSON_FILE}" ]; then
core_lines_pct=$(jq -r '.total.lines.pct' "$core_json_file") core_lines_pct="$(jq -r '.total.lines.pct' "${CORE_JSON_FILE}")"
core_statements_pct=$(jq -r '.total.statements.pct' "$core_json_file") core_statements_pct="$(jq -r '.total.statements.pct' "${CORE_JSON_FILE}")"
core_functions_pct=$(jq -r '.total.functions.pct' "$core_json_file") core_functions_pct="$(jq -r '.total.functions.pct' "${CORE_JSON_FILE}")"
core_branches_pct=$(jq -r '.total.branches.pct' "$core_json_file") core_branches_pct="$(jq -r '.total.branches.pct' "${CORE_JSON_FILE}")"
else else
core_lines_pct="N/A"; core_statements_pct="N/A"; core_functions_pct="N/A"; core_branches_pct="N/A" core_lines_pct="N/A"
echo "Core coverage-summary.json not found at: $core_json_file" >&2 # Error to stderr core_statements_pct="N/A"
core_functions_pct="N/A"
core_branches_pct="N/A"
echo "Core coverage-summary.json not found at: ${CORE_JSON_FILE}" >&2 # Error to stderr
fi fi
echo "## Code Coverage Summary" > "$comment_file" echo "## Code Coverage Summary" > "${COMMENT_FILE}"
echo "" >> "$comment_file" echo "" >> "${COMMENT_FILE}"
echo "| Package | Lines | Statements | Functions | Branches |" >> "$comment_file" echo "| Package | Lines | Statements | Functions | Branches |" >> "${COMMENT_FILE}"
echo "|---|---|---|---|---|" >> "$comment_file" echo "|---|---|---|---|---|" >> "${COMMENT_FILE}"
echo "| CLI | ${cli_lines_pct}% | ${cli_statements_pct}% | ${cli_functions_pct}% | ${cli_branches_pct}% |" >> "$comment_file" echo "| CLI | ${cli_lines_pct}% | ${cli_statements_pct}% | ${cli_functions_pct}% | ${cli_branches_pct}% |" >> "${COMMENT_FILE}"
echo "| Core | ${core_lines_pct}% | ${core_statements_pct}% | ${core_functions_pct}% | ${core_branches_pct}% |" >> "$comment_file" echo "| Core | ${core_lines_pct}% | ${core_statements_pct}% | ${core_functions_pct}% | ${core_branches_pct}% |" >> "${COMMENT_FILE}"
echo "" >> "$comment_file" echo "" >> "${COMMENT_FILE}"
# CLI Package - Collapsible Section (with full text summary from file) # CLI Package - Collapsible Section (with full text summary from file)
echo "<details>" >> "$comment_file" echo "<details>" >> "${COMMENT_FILE}"
echo "<summary>CLI Package - Full Text Report</summary>" >> "$comment_file" echo "<summary>CLI Package - Full Text Report</summary>" >> "${COMMENT_FILE}"
echo "" >> "$comment_file" echo "" >> "${COMMENT_FILE}"
echo '```text' >> "$comment_file" echo '```text' >> "${COMMENT_FILE}"
if [ -f "$cli_full_text_summary_file" ]; then if [ -f "${CLI_FULL_TEXT_SUMMARY_FILE}" ]; then
cat "$cli_full_text_summary_file" >> "$comment_file" cat "${CLI_FULL_TEXT_SUMMARY_FILE}" >> "${COMMENT_FILE}"
else else
echo "CLI full-text-summary.txt not found at: $cli_full_text_summary_file" >> "$comment_file" echo "CLI full-text-summary.txt not found at: ${CLI_FULL_TEXT_SUMMARY_FILE}" >> "${COMMENT_FILE}"
fi fi
echo '```' >> "$comment_file" echo '```' >> "${COMMENT_FILE}"
echo "</details>" >> "$comment_file" echo "</details>" >> "${COMMENT_FILE}"
echo "" >> "$comment_file" echo "" >> "${COMMENT_FILE}"
# Core Package - Collapsible Section (with full text summary from file) # Core Package - Collapsible Section (with full text summary from file)
echo "<details>" >> "$comment_file" echo "<details>" >> "${COMMENT_FILE}"
echo "<summary>Core Package - Full Text Report</summary>" >> "$comment_file" echo "<summary>Core Package - Full Text Report</summary>" >> "${COMMENT_FILE}"
echo "" >> "$comment_file" echo "" >> "${COMMENT_FILE}"
echo '```text' >> "$comment_file" echo '```text' >> "${COMMENT_FILE}"
if [ -f "$core_full_text_summary_file" ]; then if [ -f "${CORE_FULL_TEXT_SUMMARY_FILE}" ]; then
cat "$core_full_text_summary_file" >> "$comment_file" cat "${CORE_FULL_TEXT_SUMMARY_FILE}" >> "${COMMENT_FILE}"
else else
echo "Core full-text-summary.txt not found at: $core_full_text_summary_file" >> "$comment_file" echo "Core full-text-summary.txt not found at: ${CORE_FULL_TEXT_SUMMARY_FILE}" >> "${COMMENT_FILE}"
fi fi
echo '```' >> "$comment_file" echo '```' >> "${COMMENT_FILE}"
echo "</details>" >> "$comment_file" echo "</details>" >> "${COMMENT_FILE}"
echo "" >> "$comment_file" echo "" >> "${COMMENT_FILE}"
echo "_For detailed HTML reports, please see the 'coverage-reports-${{ inputs.node_version }}-${{ inputs.os }}' artifact from the main CI run._" >> "$comment_file" echo "_For detailed HTML reports, please see the 'coverage-reports-${NODE_VERSION}-${OS}' artifact from the main CI run._" >> "${COMMENT_FILE}"
- name: Post Coverage Comment - name: 'Post Coverage Comment'
uses: thollander/actions-comment-pull-request@v3 uses: 'thollander/actions-comment-pull-request@65f9e5c9a1f2cd378bd74b2e057c9736982a8e74' # ratchet:thollander/actions-comment-pull-request@v3
if: always() if: |-
${{ always() }}
with: with:
file-path: coverage-comment.md # Use the generated file directly file-path: 'coverage-comment.md' # Use the generated file directly
comment-tag: code-coverage-summary comment-tag: 'code-coverage-summary'
github-token: ${{ inputs.github_token }} github-token: '${{ inputs.github_token }}'

View File

@ -1,4 +1,4 @@
name: Generate Weekly Community Report 📊 name: 'Generate Weekly Community Report 📊'
on: on:
schedule: schedule:
@ -12,56 +12,57 @@ on:
jobs: jobs:
generate-report: generate-report:
name: Generate Report 📝 name: 'Generate Report 📝'
if: ${{ github.repository == 'google-gemini/gemini-cli' }} if: |-
runs-on: ubuntu-latest ${{ github.repository == 'google-gemini/gemini-cli' }}
runs-on: 'ubuntu-latest'
permissions: permissions:
issues: write issues: 'write'
pull-requests: read pull-requests: 'read'
discussions: read discussions: 'read'
contents: read contents: 'read'
id-token: write id-token: 'write'
steps: steps:
- name: Generate GitHub App Token 🔑 - name: 'Generate GitHub App Token 🔑'
id: generate_token id: 'generate_token'
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2 uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
with: with:
app-id: ${{ secrets.APP_ID }} app-id: '${{ secrets.APP_ID }}'
private-key: ${{ secrets.PRIVATE_KEY }} private-key: '${{ secrets.PRIVATE_KEY }}'
- name: Generate Report 📜 - name: 'Generate Report 📜'
id: report id: 'report'
env: env:
GH_TOKEN: ${{ steps.generate_token.outputs.token }} GH_TOKEN: '${{ steps.generate_token.outputs.token }}'
REPO: ${{ github.repository }} REPO: '${{ github.repository }}'
DAYS: ${{ github.event.inputs.days || '7' }} DAYS: '${{ github.event.inputs.days || 7 }}'
run: | run: |-
set -e set -e
START_DATE=$(date -u -d "$DAYS days ago" +'%Y-%m-%d') START_DATE="$(date -u -d "$DAYS days ago" +'%Y-%m-%d')"
END_DATE=$(date -u +'%Y-%m-%d') END_DATE="$(date -u +'%Y-%m-%d')"
echo "⏳ Generating report for contributions from $START_DATE to $END_DATE..." echo "⏳ Generating report for contributions from ${START_DATE} to ${END_DATE}..."
declare -A author_is_googler declare -A author_is_googler
check_googler_status() { check_googler_status() {
local author=$1 local author="$1"
if [[ "$author" == *"[bot]" ]]; then if [[ "${author}" == *"[bot]" ]]; then
author_is_googler[$author]=1 author_is_googler[${author}]=1
return 1 return 1
fi fi
if [[ -v "author_is_googler[$author]" ]]; then if [[ -v "author_is_googler[${author}]" ]]; then
return ${author_is_googler[$author]} return "${author_is_googler[${author}]}"
fi fi
if gh api "orgs/googlers/members/$author" --silent 2>/dev/null; then if gh api "orgs/googlers/members/${author}" --silent 2>/dev/null; then
echo "🧑‍💻 $author is a Googler." echo "🧑‍💻 ${author} is a Googler."
author_is_googler[$author]=0 author_is_googler[${author}]=0
else else
echo "🌍 $author is a community contributor." echo "🌍 ${author} is a community contributor."
author_is_googler[$author]=1 author_is_googler[${author}]=1
fi fi
return ${author_is_googler[$author]} return "${author_is_googler[${author}]}"
} }
googler_issues=0 googler_issues=0
@ -70,27 +71,27 @@ jobs:
non_googler_prs=0 non_googler_prs=0
echo "🔎 Fetching issues and pull requests..." echo "🔎 Fetching issues and pull requests..."
ITEMS_JSON=$(gh search issues --repo "$REPO" "created:>$START_DATE" --json author,isPullRequest --limit 1000) ITEMS_JSON="$(gh search issues --repo "${REPO}" "created:>${START_DATE}" --json author,isPullRequest --limit 1000)"
for row in $(echo "${ITEMS_JSON}" | jq -r '.[] | @base64'); do for row in $(echo "${ITEMS_JSON}" | jq -r '.[] | @base64'); do
_jq() { _jq() {
echo ${row} | base64 --decode | jq -r ${1} echo "${row}" | base64 --decode | jq -r "${1}"
} }
author=$(_jq '.author.login') author="$(_jq '.author.login')"
is_pr=$(_jq '.isPullRequest') is_pr="$(_jq '.isPullRequest')"
if [[ -z "$author" || "$author" == "null" ]]; then if [[ -z "${author}" || "${author}" == "null" ]]; then
continue continue
fi fi
if check_googler_status "$author"; then if check_googler_status "${author}"; then
if [[ "$is_pr" == "true" ]]; then if [[ "${is_pr}" == "true" ]]; then
((googler_prs++)) ((googler_prs++))
else else
((googler_issues++)) ((googler_issues++))
fi fi
else else
if [[ "$is_pr" == "true" ]]; then if [[ "${is_pr}" == "true" ]]; then
((non_googler_prs++)) ((non_googler_prs++))
else else
((non_googler_issues++)) ((non_googler_issues++))
@ -114,19 +115,19 @@ jobs:
} }
} }
}''' }'''
DISCUSSIONS_JSON=$(gh api graphql -f q="repo:$REPO created:>$START_DATE" -f query="$DISCUSSION_QUERY") DISCUSSIONS_JSON="$(gh api graphql -f q="repo:${REPO} created:>${START_DATE}" -f query="${DISCUSSION_QUERY}")"
for row in $(echo "${DISCUSSIONS_JSON}" | jq -r '.data.search.nodes[] | @base64'); do for row in $(echo "${DISCUSSIONS_JSON}" | jq -r '.data.search.nodes[] | @base64'); do
_jq() { _jq() {
echo ${row} | base64 --decode | jq -r ${1} echo "${row}" | base64 --decode | jq -r "${1}"
} }
author=$(_jq '.author.login') author="$(_jq '.author.login')"
if [[ -z "$author" || "$author" == "null" ]]; then if [[ -z "${author}" || "${author}" == "null" ]]; then
continue continue
fi fi
if check_googler_status "$author"; then if check_googler_status "${author}"; then
((googler_discussions++)) ((googler_discussions++))
else else
((non_googler_discussions++)) ((non_googler_discussions++))
@ -134,7 +135,6 @@ jobs:
done done
echo "✍️ Generating report content..." echo "✍️ Generating report content..."
REPORT_TITLE="Community Contribution Report: $START_DATE to $END_DATE"
TOTAL_ISSUES=$((googler_issues + non_googler_issues)) TOTAL_ISSUES=$((googler_issues + non_googler_issues))
TOTAL_PRS=$((googler_prs + non_googler_prs)) TOTAL_PRS=$((googler_prs + non_googler_prs))
TOTAL_DISCUSSIONS=$((googler_discussions + non_googler_discussions)) TOTAL_DISCUSSIONS=$((googler_discussions + non_googler_discussions))
@ -142,7 +142,7 @@ jobs:
REPORT_BODY=$(cat <<EOF REPORT_BODY=$(cat <<EOF
### 💖 Community Contribution Report ### 💖 Community Contribution Report
**Period:** $START_DATE to $END_DATE **Period:** ${START_DATE} to ${END_DATE}
| Category | Googlers | Community | Total | | Category | Googlers | Community | Total |
|---|---:|---:|---:| |---|---:|---:|---:|
@ -154,24 +154,29 @@ jobs:
EOF EOF
) )
echo "report_body<<EOF" >> $GITHUB_OUTPUT echo "report_body<<EOF" >> "${GITHUB_OUTPUT}"
echo "$REPORT_BODY" >> $GITHUB_OUTPUT echo "${REPORT_BODY}" >> "${GITHUB_OUTPUT}"
echo "EOF" >> $GITHUB_OUTPUT echo "EOF" >> "${GITHUB_OUTPUT}"
echo "📊 Community Contribution Report:" echo "📊 Community Contribution Report:"
echo "$REPORT_BODY" echo "${REPORT_BODY}"
- name: 🤖 Get Insights from Report - name: '🤖 Get Insights from Report'
if: steps.report.outputs.report_body != '' if: |-
uses: google-gemini/gemini-cli-action@df3f890f003d28c60a2a09d2c29e0126e4d1e2ff ${{ steps.report.outputs.report_body != '' }}
uses: 'google-github-actions/run-gemini-cli@06123c6a203eb7a964ce3be7c48479cc66059f23' # ratchet:google-github-actions/run-gemini-cli@v0
env: env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
REPOSITORY: '${{ github.repository }}'
with: with:
version: 0.1.8-rc.0 gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
OTLP_GCP_WIF_PROVIDER: ${{ secrets.OTLP_GCP_WIF_PROVIDER }} gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
OTLP_GOOGLE_CLOUD_PROJECT: ${{ secrets.OTLP_GOOGLE_CLOUD_PROJECT }} gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
settings_json: | gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{ {
"coreTools": [ "coreTools": [
"run_shell_command(gh issue list)", "run_shell_command(gh issue list)",
@ -180,7 +185,7 @@ jobs:
"run_shell_command(gh search prs)" "run_shell_command(gh search prs)"
] ]
} }
prompt: | prompt: |-
You are a helpful assistant that analyzes community contribution reports. You are a helpful assistant that analyzes community contribution reports.
Based on the following report, please provide a brief summary and highlight any interesting trends or potential areas for improvement. Based on the following report, please provide a brief summary and highlight any interesting trends or potential areas for improvement.

View File

@ -58,7 +58,7 @@ To install the latest nightly build, use the `@nightly` tag:
npm install -g @google/gemini-cli@nightly npm install -g @google/gemini-cli@nightly
``` ```
We also run a Google cloud build called [release-docker.yml](../.gcp/release-docker.yaml). Which publishes the sandbox docker to match your release. This will also be moved to GH and combined with the main release file once service account permissions are sorted out. We also run a Google cloud build called [release-docker.yml](../.gcp/release-docker.yml). Which publishes the sandbox docker to match your release. This will also be moved to GH and combined with the main release file once service account permissions are sorted out.
### After the Release ### After the Release