Skip to content

Commit bd91d7a

Browse files
authored
Try and address TOCTOU issues in gemini-cli.yml (#187)
This ensures we check out the data from the event (instead of the head). I am struggling to test this in my local branch. I keep getting failed invocations or tool command errors.
1 parent 2085640 commit bd91d7a

1 file changed

Lines changed: 67 additions & 150 deletions

File tree

.github/workflows/gemini-cli.yml

Lines changed: 67 additions & 150 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet: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 }}'
@@ -227,29 +140,24 @@ jobs:
227140
228141
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.
229142
230-
## Context
143+
## Steps
231144
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 }}`
145+
Start by running these commands to gather the required data and context:
240146
241-
## User Request
242-
243-
The user has sent the following request:
244-
`${{ steps.get_context.outputs.user_request }}`
147+
1. Run: echo "${DESCRIPTION}" to get a description of the pull request or issue
148+
2. Run: echo "${EVENT_NAME}" to learn what kind of GitHub event triggered this request
149+
3. Run: echo "${IS_PULL_REQUEST}" to learn whether this is a Pull Request (PR) or Issue
150+
4. Run: echo "${ISSUE_NUMBER}" to get the PR or Issue number
151+
5. Run: echo "${REPOSITORY}" to get the github repository in <OWNER>/<REPO> format
152+
6. Run: echo "${USER_REQUEST}" to get the user's request
245153
246154
## How to Respond to Issues, PR Comments, and Questions
247155
248156
This workflow supports three main scenarios:
249157
250158
1. **Creating a Fix for an Issue**
251159
- 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`).
160+
- Use available tools to gather all relevant context (e.g., `gh issue view`, `gh issue comments list` `gh pr diff`, `cat`, `head`, `tail`).
253161
- Identify the root cause of the problem before proceeding.
254162
- **Show and maintain a plan as a checklist**:
255163
- 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 +170,63 @@ jobs:
262170
- [ ] Update documentation
263171
- [ ] Verify the fix and close the issue
264172
```
265-
- Use: `gh pr comment "${ISSUE_NUMBER}" --body "<plan>"` or `gh issue comment "${ISSUE_NUMBER}" --body "<plan>"` to post the initial plan.
173+
- Use: `gh issue comment "${ISSUE_NUMBER}" --body "<plan>"` to post the initial plan.
266174
- As you make progress, keep the checklist visible and up to date by editing the same comment (check off completed tasks with `- [x]`).
267175
- 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>"`
176+
1. Find the comment ID for the checklist: `gh issue comment list "${ISSUE_NUMBER}"`
177+
2. Edit the comment with the updated checklist: `gh issue comment --edit "<comment-id>" --body "<updated plan>"`
272178
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.
273179
- If the fix requires code changes, determine which files and lines are affected. If clarification is needed, note any questions for the user.
274180
- 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.
275181
- 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.
276182
- **Branching and Committing**:
277183
- **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.
184+
- 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.
279185
- `git add .`
280186
- `git commit -m "feat: <describe the change>"`
281187
- `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`
188+
- 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}`.
189+
- `git checkout -b "gemini/fix-${ISSUE_NUMBER}"`
284190
- `git add .`
285191
- `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`
192+
- `git push origin "gemini/fix-${ISSUE_NUMBER}"`
193+
- After pushing, create a pull request: `gh pr create --title "Fixes #${ISSUE_NUMBER}: <short title>" --body "This PR addresses issue #${ISSUE_NUMBER}."`
194+
- 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"`
292195
293196
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.
197+
- Read the specific description and context.
198+
- Use tools like `gh pr diff` and `cat` to understand the code and discussion.
199+
- 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.
297200
- **Committing Changes**: The correct PR branch is already checked out. Simply add, commit, and push your changes.
298201
- `git add .`
299202
- `git commit -m "fix: address review comments"`
300203
- `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`
204+
- If the description is a question, answer it directly and clearly, referencing code or documentation as needed.
205+
- Document your response in `response.md` in markdown format and post it as a comment: `gh issue comment "${ISSUE_NUMBER}" --body-file "response.md"`
303206
304207
3. **Answering Any Question on an Issue**
305-
- Read the question and the full issue context using `gh issue view` and related tools.
208+
- Read the description and the full context.
306209
- Research or analyze the codebase as needed to provide an accurate answer.
307210
- 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`
211+
- 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"`
309212
310213
## Guidelines
311214
312215
- **Be concise and actionable.** Focus on solving the user's problem efficiently.
313216
- **Always commit and push your changes if you modify code or documentation.**
314217
- **If you are unsure about the fix or answer, explain your reasoning and ask clarifying questions.**
315218
- **Follow project conventions and best practices.**
219+
220+
- name: 'Print failure'
221+
if: |-
222+
${{ failure() && !cancelled() }}
223+
env:
224+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
225+
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
226+
MESSAGE: |-
227+
🤖 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.
228+
REPOSITORY: '${{ github.repository }}'
229+
run: |-
230+
gh issue comment "${ISSUE_NUMBER}" \
231+
--body "${MESSAGE}" \
232+
--repo "${REPOSITORY}"

0 commit comments

Comments
 (0)