Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 7 additions & 50 deletions .gemini/ci/pr-review/PROMPT.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,13 @@
<CONTEXT>
**GitHub Repository**: ${REPOSITORY}
**Pull Request Number**: ${PULL_REQUEST_NUMBER}
**Additional User Instructions**: ${ADDITIONAL_CONTEXT}
**Pull Review Details**: use `pull_request_read.get` tool to get the title, body, and metadata about the pull request.
**Code Changes**: call the `pull_request_read.get_diff` tool to retrieve the changes.
**GitHub Repository**: ${REPOSITORY}
**Pull Request Number**: ${PULL_REQUEST_NUMBER}
**Additional User Instructions**: ${ADDITIONAL_CONTEXT}
</CONTEXT>

<PROTOCOL>
The `code-review-commons` skill is ALREADY loaded and active. Proceed directly to analyzing the diffs using the `github` MCP tools. Then submit review following the exact structure and rules in the `<SUBMIT_REVIEW>` section.
The `code-review-commons` skill is ALREADY loaded and active. Proceed directly to analyzing the diffs using the `github` MCP tools.
</PROTOCOL>

<SUBMIT_REVIEW>
**Review Comment Formatting**

- **Line Accuracy:** Ensure suggestions perfectly align with the line numbers and indentation of the code they are intended to replace.

- Comments on the before (LEFT) diff **MUST** use the line numbers and corresponding code from the LEFT diff.

- Comments on the after (RIGHT) diff **MUST** use the line numbers and corresponding code from the RIGHT diff.

1. **Create Pending Review:** Call `create_pending_pull_request_review`. Ignore errors like "can only have one pending review per pull request" and proceed to the next step.

2. **Add Comments and Suggestions:** For each formulated review comment, call `add_comment_to_pending_review`.

2a. For each suggested change, structure the comment payload using this exact template:

<COMMENT>
[{{SEVERITY}}] {{COMMENT_TEXT}}

```suggestion
{{CODE_SUGGESTION}}
```
</COMMENT>

2b. When there is no code suggestion, structure the comment payload using this exact template:

<COMMENT>
[{{SEVERITY}}] {{COMMENT_TEXT}}
</COMMENT>

3. **Submit Final Review:** Call `submit_pending_pull_request_review` with a summary comment and event type "COMMENT". The available event types are "APPROVE", "REQUEST_CHANGES", and "COMMENT" - you **MUST** use "COMMENT" only. **DO NOT** use "APPROVE" or "REQUEST_CHANGES" event types. The summary comment **MUST** use this exact markdown format:

## 📋 Review Summary

A brief, high-level assessment of the Pull Request's objective and quality (2-3 sentences).

## 🔍 General Feedback

- A bulleted list of general observations, positive highlights, or recurring patterns not suitable for inline comments.
- Keep this section concise and do not repeat details already covered in inline comments.
</SUBMIT_REVIEW>

# Pull Request Review Guidelines

You are performing an automated Pull Request review for this repository.
Expand All @@ -59,10 +16,10 @@ To ensure high-quality, clean, and non-spammy feedback, you MUST strictly adhere
## 1. Environment & Context
- The target repository name is provided in the `REPOSITORY` environment variable.
- The Pull Request number is provided in the `PULL_REQUEST_NUMBER` environment variable.
- When calling any GitHub MCP tools (such as `pull_request_read.get`, `pull_request_read.get_diff`, `create_pending_pull_request_review`, `add_comment_to_pending_review`, or `submit_pending_pull_request_review`), you MUST use these exact literal values:
- When calling any GitHub MCP tools, you MUST use these exact literal values:
- `repository`: "${REPOSITORY}"
- `pull_request_number`: ${PULL_REQUEST_NUMBER} (as a literal numeric integer, e.g. 11. You MUST pass it as a number, do NOT wrap it in quotes!)
- **CRITICAL:** Do NOT use placeholder variables, string templates (like `"$REPOSITORY"` or `"$PULL_REQUEST_NUMBER"`), or environment variable references inside your Python tool call arguments. You MUST resolve and pass the literal values directly.
- `pull_request_number`: ${PULL_REQUEST_NUMBER} (as a literal numeric integer. You MUST pass it as a number, do NOT wrap it in quotes!)
- **CRITICAL:** Do NOT use placeholder variables or string templates inside your Python tool call arguments.

## 2. Anti-Spam Guardrail
- **CRITICAL:** First, fetch and read the Pull Request's existing review comments using `pull_request_read`.
Expand Down
141 changes: 0 additions & 141 deletions .github/workflows/gemini-dispatch.yml

This file was deleted.

96 changes: 46 additions & 50 deletions .github/workflows/gemini-review.yml
Original file line number Diff line number Diff line change
@@ -1,93 +1,89 @@
name: 'Gemini Review'
name: 'Gemini PR Review'

on:
workflow_call:
inputs:
additional_context:
type: 'string'
description: 'Any additional context from the request'
required: false

pull_request:
types: [opened, synchronize]
issue_comment:
types: [created]

concurrency:
group: '${{ github.workflow }}-review-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
group: '${{ github.workflow }}-${{ github.event.pull_request.number || github.event.issue.number }}'
cancel-in-progress: true

permissions:
contents: read
pull-requests: write

defaults:
run:
shell: 'bash'
issues: write

jobs:
review:
# Only run on PRs (not forks) OR on PR comments starting with the command from authorized users
if: >-
(github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork) ||
(github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '@gemini-cli /review') && contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association))
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
ref: refs/pull/${{ github.event.pull_request.number || github.event.issue.number }}/head
fetch-depth: 0

- name: Load Gemini Configurations for PR Review
- name: Acknowledge Command (Reaction)
if: github.event_name == 'issue_comment'
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api -X POST /repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions -f content='eyes'

- name: Extract Context & Load Configs
id: config
working-directory: .gemini/ci/pr-review
env:
REPOSITORY: ${{ github.repository }}
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
ADDITIONAL_CONTEXT: ${{ inputs.additional_context }}
RAW_COMMENT: ${{ github.event.comment.body || '' }}
run: |
python3 -c '
import os
content = open("PROMPT.md").read()
content = content.replace("${REPOSITORY}", os.environ["REPOSITORY"])
content = content.replace("${PULL_REQUEST_NUMBER}", os.environ["PULL_REQUEST_NUMBER"])
content = content.replace("${ADDITIONAL_CONTEXT}", os.environ.get("ADDITIONAL_CONTEXT", ""))
open("PROMPT_RESOLVED.md", "w").write(content)
'

echo "=== DEBUG: PROMPT_RESOLVED.md ==="
cat PROMPT_RESOLVED.md
echo "=================================="

# 1. Extract additional context from the comment (if any)
ADDITIONAL_CONTEXT="None"
if [[ "$RAW_COMMENT" == *"@gemini-cli /review"* ]]; then
ADDITIONAL_CONTEXT=$(echo "$RAW_COMMENT" | sed 's/^@gemini-cli \/review//' | xargs)
[ -z "$ADDITIONAL_CONTEXT" ] && ADDITIONAL_CONTEXT="None"
fi

# Export variables so envsubst can access them
export REPOSITORY PULL_REQUEST_NUMBER ADDITIONAL_CONTEXT

# 2. Safely read files and set GitHub Outputs
{
echo "settings<<EOF"
echo "settings<<EOF_DELIM"
cat settings.json
echo ""
echo "EOF"

echo "prompt<<EOF"
cat PROMPT_RESOLVED.md
echo ""
echo "EOF"

echo "extensions<<EOF"
echo "EOF_DELIM"

echo "extensions<<EOF_DELIM"
cat extensions.json
echo ""
echo "EOF"
echo "EOF_DELIM"

echo "prompt<<EOF_DELIM"
envsubst '${REPOSITORY} ${PULL_REQUEST_NUMBER} ${ADDITIONAL_CONTEXT}' < PROMPT.md
echo ""
echo "EOF_DELIM"
} >> "$GITHUB_OUTPUT"

- name: Run Gemini CLI for PR Review
- name: Run Gemini CLI
uses: google-github-actions/run-gemini-cli@v0.1.22
env:
Comment thread
q4rk marked this conversation as resolved.
GEMINI_CLI_TRUST_WORKSPACE: true
GEMINI_CLI_TRUST_WORKSPACE: 'true'
GITHUB_TOKEN: ${{ github.token }}
ISSUE_TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}'
ISSUE_BODY: '${{ github.event.pull_request.body || github.event.issue.body }}'
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
REPOSITORY: ${{ github.repository }}
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
with:
gemini_api_key: ${{ secrets.GEMINI_API_KEY }}
workflow_name: 'gemini-review'
gemini_cli_version: 'latest'
gemini_model: 'gemini-2.5-flash'
# Explicitly set the PR number to handle `issue_comment` triggers (which GitHub treats as issues, not PRs)
github_pr_number: '${{ github.event.pull_request.number }}'
github_pr_number: ${{ github.event.pull_request.number || github.event.issue.number }}
prompt: ${{ steps.config.outputs.prompt }}
settings: ${{ steps.config.outputs.settings }}
extensions: ${{ steps.config.outputs.extensions }}
gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || true) }}'
extensions: ${{ steps.config.outputs.extensions }}
10 changes: 10 additions & 0 deletions another_bad_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import sqlite3

def get_user_data(username):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
query = f"SELECT * FROM users WHERE username = '{username}'"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CRITICAL] SQL Injection Vulnerability: The get_user_data function is vulnerable to SQL injection. User input (username) is directly embedded into the SQL query via an f-string. This allows attackers to inject malicious SQL code.

Suggested change
query = f"SELECT * FROM users WHERE username = '{username}'"
import sqlite3
def get_user_data(username):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
query = "SELECT * FROM users WHERE username = ?"
cursor.execute(query, (username,))
return cursor.fetchall()

cursor.execute(query)
return cursor.fetchall()

unused_var = 10

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MINOR] Unused Variable: The variable unused_var is defined but never used. Consider removing it or using it if it serves a purpose.

Loading