Skip to content

Commit 90598f5

Browse files
committed
Try and address TOCTOU issues in gemini-cli.yml
This ensures we check out the data from the event (instead of the head).
1 parent a3bf790 commit 90598f5

1 file changed

Lines changed: 87 additions & 154 deletions

File tree

.github/workflows/gemini-cli.yml

Lines changed: 87 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ defaults:
2222

2323
permissions:
2424
contents: 'write'
25-
id-token: 'write'
2625
pull-requests: 'write'
2726
issues: 'write'
2827

@@ -32,7 +31,6 @@ jobs:
3231
# For private repos, users who have access to the repo are considered trusted.
3332
# For public repos, users who members, owners, or collaborators are considered trusted.
3433
if: |-
35-
github.event_name == 'workflow_dispatch' ||
3634
(
3735
github.event_name == 'issues' && github.event.action == 'opened' &&
3836
contains(github.event.issue.body, '@gemini-cli') &&
@@ -69,6 +67,8 @@ jobs:
6967
timeout-minutes: 10
7068
runs-on: 'ubuntu-latest'
7169
steps:
70+
# Mint a token so that the comments show up as gemini-cli instead of
71+
# github-actions.
7272
- name: 'Generate GitHub App Token'
7373
id: 'generate_token'
7474
if: |-
@@ -78,133 +78,46 @@ jobs:
7878
app-id: '${{ vars.APP_ID }}'
7979
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
8080

81-
- name: 'Get context from event'
82-
id: 'get_context'
81+
# Tell the user that we're working on their request.
82+
- name: 'Acknowledge request'
8383
env:
84-
EVENT_NAME: '${{ github.event_name }}'
85-
EVENT_PAYLOAD: '${{ toJSON(github.event) }}'
84+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
85+
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
86+
MESSAGE: |-
87+
🤖 Hi @${{ github.actor }} - I am working on your request now!
88+
REPOSITORY: '${{ github.repository }}'
8689
run: |-
87-
set -euo pipefail
88-
89-
USER_REQUEST=""
90-
ISSUE_NUMBER=""
91-
IS_PR="false"
92-
93-
if [[ "${EVENT_NAME}" == "issues" ]]; then
94-
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.body)
95-
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
96-
elif [[ "${EVENT_NAME}" == "issue_comment" ]]; then
97-
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .comment.body)
98-
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
99-
if [[ $(echo "${EVENT_PAYLOAD}" | jq -r .issue.pull_request) != "null" ]]; then
100-
IS_PR="true"
101-
fi
102-
elif [[ "${EVENT_NAME}" == "pull_request_review" ]]; then
103-
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .review.body)
104-
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .pull_request.number)
105-
IS_PR="true"
106-
elif [[ "${EVENT_NAME}" == "pull_request_review_comment" ]]; then
107-
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .comment.body)
108-
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .pull_request.number)
109-
IS_PR="true"
110-
fi
111-
112-
# Clean up user request
113-
USER_REQUEST=$(echo "${USER_REQUEST}" | sed 's/.*@gemini-cli//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
114-
115-
{
116-
echo "user_request=${USER_REQUEST}"
117-
echo "issue_number=${ISSUE_NUMBER}"
118-
echo "is_pr=${IS_PR}"
119-
} >> "${GITHUB_OUTPUT}"
90+
gh issue comment "${ISSUE_NUMBER}" \
91+
--body "${MESSAGE}" \
92+
--repo "${REPOSITORY}"
93+
94+
# Check out the SHA that corresponds to the event for when the issue
95+
# fired. This protects against attacks where new commits are pushed
96+
# between when a maintainer approved running the workflows and when the
97+
# workflow actually starts.
98+
- name: 'Checkout pull request'
99+
uses: 'actions/checkout@v5'
100+
with:
101+
ref: '${{ github.event.pull_request.merge_commit_sha || github.event.pull_request.head.sha || github.sha }}'
120102

103+
# In case the Gemini CLI needs to make commits to the repo, configure it's
104+
# identity.
121105
- name: 'Set up git user for commits'
122106
run: |-
123107
git config --global user.name 'gemini-cli[bot]'
124108
git config --global user.email 'gemini-cli[bot]@users.noreply.github.com'
125109
126-
- name: 'Checkout PR branch'
127-
if: |-
128-
${{ steps.get_context.outputs.is_pr == 'true' }}
129-
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
130-
with:
131-
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
132-
repository: '${{ github.repository }}'
133-
ref: 'refs/pull/${{ steps.get_context.outputs.issue_number }}/head'
134-
fetch-depth: 0
135-
136-
- name: 'Checkout main branch'
137-
if: |-
138-
${{ steps.get_context.outputs.is_pr == 'false' }}
139-
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
140-
with:
141-
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
142-
repository: '${{ github.repository }}'
143-
fetch-depth: 0
144-
145-
- name: 'Acknowledge request'
146-
env:
147-
GITHUB_ACTOR: '${{ github.actor }}'
148-
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
149-
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
150-
REPOSITORY: '${{ github.repository }}'
151-
REQUEST_TYPE: '${{ steps.get_context.outputs.request_type }}'
152-
run: |-
153-
set -euo pipefail
154-
MESSAGE="@${GITHUB_ACTOR} I've received your request and I'm working on it now! 🤖"
155-
if [[ -n "${MESSAGE}" ]]; then
156-
gh issue comment "${ISSUE_NUMBER}" \
157-
--body "${MESSAGE}" \
158-
--repo "${REPOSITORY}"
159-
fi
160-
161-
- name: 'Get description'
162-
id: 'get_description'
163-
env:
164-
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
165-
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
166-
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
167-
run: |-
168-
set -euo pipefail
169-
if [[ "${IS_PR}" == "true" ]]; then
170-
DESCRIPTION=$(gh pr view "${ISSUE_NUMBER}" --json body --template '{{.body}}')
171-
else
172-
DESCRIPTION=$(gh issue view "${ISSUE_NUMBER}" --json body --template '{{.body}}')
173-
fi
174-
{
175-
echo "description<<EOF"
176-
echo "${DESCRIPTION}"
177-
echo "EOF"
178-
} >> "${GITHUB_OUTPUT}"
179-
180-
- name: 'Get comments'
181-
id: 'get_comments'
182-
env:
183-
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
184-
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
185-
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
186-
run: |-
187-
set -euo pipefail
188-
if [[ "${IS_PR}" == "true" ]]; then
189-
COMMENTS=$(gh pr view "${ISSUE_NUMBER}" --json comments --template '{{range .comments}}{{.author.login}}: {{.body}}{{"\n"}}{{end}}')
190-
else
191-
COMMENTS=$(gh issue view "${ISSUE_NUMBER}" --json comments --template '{{range .comments}}{{.author.login}}: {{.body}}{{"\n"}}{{end}}')
192-
fi
193-
{
194-
echo "comments<<EOF"
195-
echo "${COMMENTS}"
196-
echo "EOF"
197-
} >> "${GITHUB_OUTPUT}"
198-
199110
- name: 'Run Gemini'
200111
id: 'run_gemini'
201112
uses: './'
202113
env:
114+
DESCRIPTION: '${{ github.event.pull_request.body || github.event.issue.body }}'
115+
EVENT_NAME: '${{ github.event_name }}'
203116
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
117+
IS_PULL_REQUEST: '${{ !!github.event.pull_request }}'
118+
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
204119
REPOSITORY: '${{ github.repository }}'
205-
USER_REQUEST: '${{ steps.get_context.outputs.user_request }}'
206-
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
207-
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
120+
USER_REQUEST: '${{ github.event.comment.body || github.event.review.body || github.event.issue.body }}'
208121
with:
209122
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
210123
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
@@ -217,39 +130,50 @@ jobs:
217130
{
218131
"debug": ${{ fromJSON(env.DEBUG || env.ACTIONS_STEP_DEBUG || false) }},
219132
"maxSessionTurns": 50,
220-
"telemetry": {
221-
"enabled": true,
222-
"target": "gcp"
223-
}
133+
"coreTools": [
134+
"glob",
135+
"list_directory",
136+
"read_file",
137+
"read_many_files",
138+
"replace",
139+
"run_shell_command(cat)",
140+
"run_shell_command(echo)",
141+
"run_shell_command(git)",
142+
"run_shell_command(gh issue comment list)",
143+
"run_shell_command(gh issue comment)",
144+
"run_shell_command(gh pr create)",
145+
"run_shell_command(gh pr diff)",
146+
"run_shell_command(grep)",
147+
"run_shell_command(head)",
148+
"run_shell_command(ls)",
149+
"run_shell_command(tail)",
150+
"search_file_content",
151+
"write_file"
152+
]
224153
}
225154
prompt: |-
226155
## Role
227156
228157
You are a helpful AI assistant invoked via a CLI interface in a GitHub workflow. You have access to tools to interact with the repository and respond to the user.
229158
230-
## Context
159+
## Steps
231160
232-
- **Repository**: `${{ github.repository }}`
233-
- **Triggering Event**: `${{ github.event_name }}`
234-
- **Issue/PR Number**: `${{ steps.get_context.outputs.issue_number }}`
235-
- **Is this a PR?**: `${{ steps.get_context.outputs.is_pr }}`
236-
- **Issue/PR Description**:
237-
`${{ steps.get_description.outputs.description }}`
238-
- **Comments**:
239-
`${{ steps.get_comments.outputs.comments }}`
161+
Start by running these commands to gather the required data and context:
240162
241-
## User Request
242-
243-
The user has sent the following request:
244-
`${{ steps.get_context.outputs.user_request }}`
163+
1. Run: echo "${DESCRIPTION}" to get a description of the pull request or issue
164+
2. Run: echo "${EVENT_NAME}" to learn what kind of GitHub event triggered this request
165+
3. Run: echo "${IS_PULL_REQUEST}" to learn whether this is a Pull Request (PR) or Issue
166+
4. Run: echo "${ISSUE_NUMBER}" to get the PR or Issue number
167+
5. Run: echo "${REPOSITORY}" to get the github repository in <OWNER>/<REPO> format
168+
6. Run: echo "${USER_REQUEST}" to get the user's request
245169
246170
## How to Respond to Issues, PR Comments, and Questions
247171
248172
This workflow supports three main scenarios:
249173
250174
1. **Creating a Fix for an Issue**
251175
- Carefully read the user request and the related issue or PR description.
252-
- Use available tools to gather all relevant context (e.g., `gh issue view`, `gh pr view`, `gh pr diff`, `cat`, `head`, `tail`).
176+
- Use available tools to gather all relevant context (e.g., `gh issue comment`, `gh pr diff`, `cat`, `head`, `tail`).
253177
- Identify the root cause of the problem before proceeding.
254178
- **Show and maintain a plan as a checklist**:
255179
- At the very beginning, outline the steps needed to resolve the issue or address the request and post them as a checklist comment on the issue or PR (use GitHub markdown checkboxes: `- [ ] Task`).
@@ -262,54 +186,63 @@ jobs:
262186
- [ ] Update documentation
263187
- [ ] Verify the fix and close the issue
264188
```
265-
- Use: `gh pr comment "${ISSUE_NUMBER}" --body "<plan>"` or `gh issue comment "${ISSUE_NUMBER}" --body "<plan>"` to post the initial plan.
189+
- Use: `gh issue comment "${ISSUE_NUMBER}" --body "<plan>"` to post the initial plan.
266190
- As you make progress, keep the checklist visible and up to date by editing the same comment (check off completed tasks with `- [x]`).
267191
- To update the checklist:
268-
1. Find the comment ID for the checklist (use `gh pr comment list "${ISSUE_NUMBER}"` or `gh issue comment list "${ISSUE_NUMBER}"`).
269-
2. Edit the comment with the updated checklist:
270-
- For PRs: `gh pr comment --edit <comment-id> --body "<updated plan>"`
271-
- For Issues: `gh issue comment --edit <comment-id> --body "<updated plan>"`
192+
1. Find the comment ID for the checklist: `gh issue comment list "${ISSUE_NUMBER}"`
193+
2. Edit the comment with the updated checklist: `gh issue comment --edit "<comment-id>" --body "<updated plan>"`
272194
3. The checklist should only be maintained as a comment on the issue or PR. Do not track or update the checklist in code files.
273195
- If the fix requires code changes, determine which files and lines are affected. If clarification is needed, note any questions for the user.
274196
- Make the necessary code or documentation changes using the available tools (e.g., `write_file`). Ensure all changes follow project conventions and best practices. Reference all shell variables as `"${VAR}"` (with quotes and braces) to prevent errors.
275197
- Run any relevant tests or checks to verify the fix works as intended. If possible, provide evidence (test output, screenshots, etc.) that the issue is resolved.
276198
- **Branching and Committing**:
277199
- **NEVER commit directly to the `main` branch.**
278-
- If you are working on a **pull request** (`IS_PR` is `true`), the correct branch is already checked out. Simply commit and push to it.
200+
- If you are working on a **pull request** (`IS_PULL_REQUEST` is `true`), the correct branch is already checked out. Simply commit and push to it.
279201
- `git add .`
280202
- `git commit -m "feat: <describe the change>"`
281203
- `git push`
282-
- If you are working on an **issue** (`IS_PR` is `false`), create a new branch for your changes. A good branch name would be `issue/${ISSUE_NUMBER}/<short-description>`.
283-
- `git checkout -b issue/${ISSUE_NUMBER}/my-fix`
204+
- If you are working on an **issue** (`IS_PULL_REQUEST` is `false`), create a new branch for your changes. The branch name should be `gemini/fix-${ISSUE_NUMBER}`.
205+
- `git checkout -b "gemini/fix-${ISSUE_NUMBER}"`
284206
- `git add .`
285207
- `git commit -m "feat: <describe the fix>"`
286-
- `git push origin issue/${ISSUE_NUMBER}/my-fix`
287-
- After pushing, you can create a pull request: `gh pr create --title "Fixes #${ISSUE_NUMBER}: <short title>" --body "This PR addresses issue #${ISSUE_NUMBER}."`
288-
- Summarize what was changed and why in a markdown file: `write_file("response.md", "<your response here>")`
289-
- Post the response as a comment:
290-
- For PRs: `gh pr comment "${ISSUE_NUMBER}" --body-file response.md`
291-
- For Issues: `gh issue comment "${ISSUE_NUMBER}" --body-file response.md`
208+
- `git push origin "gemini/fix-${ISSUE_NUMBER}"`
209+
- After pushing, create a pull request: `gh pr create --title "Fixes #${ISSUE_NUMBER}: <short title>" --body "This PR addresses issue #${ISSUE_NUMBER}."`
210+
- Summarize what was changed and why in `response.md` in markdown format and post it as a comment: `gh issue comment "${ISSUE_NUMBER}" --body-file "response.md"`
292211
293212
2. **Addressing Comments on a Pull Request**
294-
- Read the specific comment and the context of the PR.
295-
- Use tools like `gh pr view`, `gh pr diff`, and `cat` to understand the code and discussion.
296-
- If the comment requests a change or clarification, follow the same process as for fixing an issue: create a checklist plan, implement, test, and commit any required changes, updating the checklist as you go.
213+
- Read the specific description and context.
214+
- Use tools like `gh pr diff` and `cat` to understand the code and discussion.
215+
- If the description requests a change or clarification, follow the same process as for fixing an issue: create a checklist plan, implement, test, and commit any required changes, updating the checklist as you go.
297216
- **Committing Changes**: The correct PR branch is already checked out. Simply add, commit, and push your changes.
298217
- `git add .`
299218
- `git commit -m "fix: address review comments"`
300219
- `git push`
301-
- If the comment is a question, answer it directly and clearly, referencing code or documentation as needed.
302-
- Document your response in `response.md` and post it as a PR comment: `gh pr comment "${ISSUE_NUMBER}" --body-file response.md`
220+
- If the description is a question, answer it directly and clearly, referencing code or documentation as needed.
221+
- Document your response in `response.md` in markdown format and post it as a comment: `gh issue comment "${ISSUE_NUMBER}" --body-file "response.md"`
303222
304223
3. **Answering Any Question on an Issue**
305-
- Read the question and the full issue context using `gh issue view` and related tools.
224+
- Read the description and the full context.
306225
- Research or analyze the codebase as needed to provide an accurate answer.
307226
- If the question requires code or documentation changes, follow the fix process above, including creating and updating a checklist plan and **creating a new branch for your changes as described in section 1.**
308-
- Write a clear, concise answer in `response.md` and post it as an issue comment: `gh issue comment "${ISSUE_NUMBER}" --body-file response.md`
227+
- Write a clear, concise answer in `response.md` in markdown format and post it as a comment: `gh issue comment "${ISSUE_NUMBER}" --body-file "response.md"`
309228
310229
## Guidelines
311230
312231
- **Be concise and actionable.** Focus on solving the user's problem efficiently.
313232
- **Always commit and push your changes if you modify code or documentation.**
314233
- **If you are unsure about the fix or answer, explain your reasoning and ask clarifying questions.**
315234
- **Follow project conventions and best practices.**
235+
236+
- name: 'Print failure'
237+
if: |-
238+
${{ failure() && !cancelled() }}
239+
env:
240+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
241+
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
242+
MESSAGE: |-
243+
🤖 I'm sorry @${{ github.actor }}, but I was unable to process your request. Please [see the logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more details.
244+
REPOSITORY: '${{ github.repository }}'
245+
run: |-
246+
gh issue comment "${ISSUE_NUMBER}" \
247+
--body "${MESSAGE}" \
248+
--repo "${REPOSITORY}"

0 commit comments

Comments
 (0)