Skip to content
Merged
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
50 changes: 50 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Claude Code

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
Comment on lines +8 to +9
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the workflow file
git ls-files | grep -E 'claude\.yml'

Repository: ESPresense/ESPresense-companion

Length of output: 104


🏁 Script executed:

# Read the workflow file to see lines 8-9 and 19
cat -n .github/workflows/claude.yml

Repository: ESPresense/ESPresense-companion

Length of output: 2311


Drop issues.assigned to prevent unintended re-executions.

The condition on line 19 checks if the @claude mention exists in the issue body or title. When an issue is assigned, the issues.assigned event fires and re-evaluates this condition. If the original issue creation contained the mention, the workflow triggers again even though no new mention was made. Removing assigned ensures the workflow only runs on initial issue creation (when the mention would be new) and on explicit mentions in comments.

Suggested change
   issues:
-    types: [opened, assigned]
+    types: [opened]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
issues:
types: [opened, assigned]
issues:
types: [opened]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/claude.yml around lines 8 - 9, The workflow currently
listens to the issues event with types [opened, assigned] which causes re-runs
when an issue is assigned; update the event config to remove the assigned type
so it only triggers on new issues (keep the issues.types array containing only
opened) and ensure any logic that checks for the `@claude` mention (the condition
referenced in the workflow) remains unchanged so the workflow only executes on
initial issue creation or explicit comment triggers.

pull_request_review:
types: [submitted]

jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
Comment on lines +15 to +20
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# Check if the workflow file exists and read it
if [ -f ".github/workflows/claude.yml" ]; then
  echo "=== File found, reading content ==="
  cat -n ".github/workflows/claude.yml"
else
  echo "File not found"
fi

Repository: ESPresense/ESPresense-companion

Length of output: 2347


🏁 Script executed:

# Search for any reference to CLAUDE_CODE_OAUTH_TOKEN in the workflow
rg "CLAUDE_CODE_OAUTH_TOKEN" ".github/workflows/"

Repository: ESPresense/ESPresense-companion

Length of output: 178


🌐 Web query:

GitHub Actions author_association field availability issue_comment pull_request_review_comment pull_request_review issues event context

💡 Result:

The author_association field is available in the github.event context for GitHub Actions workflows triggered by the specified events, but its location varies by event type. It indicates the author's association with the repository (e.g., OWNER, MEMBER, CONTRIBUTOR, NONE) [1][2][3]. For issues event (issue opened/edited/closed, etc.): - Available as github.event.issue.author_association [4]. For issue_comment event: - Available as github.event.comment.author_association. The comment object in the webhook payload includes author_association, matching the REST API structure for issue comments [2][5][6]. For pull_request_review_comment event: - Available as github.event.comment.author_association. The payload structure mirrors issue_comment, with comment object containing author_association [7][8]. For pull_request_review event: - Available as github.event.review.author_association. Examples use github.event.review.author_association to check permissions [7][9]. No availability issues identified in recent sources (up to 2026); it is standard in these webhook payloads used by GitHub Actions [10][11][12]. Older discussions (e.g., 2020 StackOverflow [13]) noted GraphQL needs, but REST/webhook payloads include it directly. Potential bugs like incorrect values (e.g., CONTRIBUTOR instead of MEMBER) exist but do not affect field availability [4].

Citations:


Add author-association gating before running Claude.

The current if condition only checks for @claude mentions and does not verify the author's association with the repository. This allows untrusted users (with NONE or CONTRIBUTOR association) to trigger the workflow, at which point line 37 injects CLAUDE_CODE_OAUTH_TOKEN into the job context and passes it to a third-party action.

Suggested hardening
 if: |
-  (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
-  (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
-  (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
-  (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
+  (
+    github.event_name == 'issue_comment' &&
+    contains(github.event.comment.body, '@claude') &&
+    contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
+  ) ||
+  (
+    github.event_name == 'pull_request_review_comment' &&
+    contains(github.event.comment.body, '@claude') &&
+    contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
+  ) ||
+  (
+    github.event_name == 'pull_request_review' &&
+    contains(github.event.review.body, '@claude') &&
+    contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.review.author_association)
+  ) ||
+  (
+    github.event_name == 'issues' &&
+    (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) &&
+    contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.issue.author_association)
+  )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/claude.yml around lines 15 - 20, The workflow currently
triggers on any `@claude` mention without verifying the actor's repository
association—update the if condition to require an allowed author_association
(e.g., OWNER, MEMBER, or COLLABORATOR) for the relevant event payloads in
addition to the contains(..., '@claude') checks; specifically add checks using
github.event.comment.author_association for issue_comment and
pull_request_review_comment, github.event.review.user.author_association for
pull_request_review (while still checking github.event.review.body), and
github.event.issue.author_association for issues (and issues.title), and combine
each association check with the existing contains(...) terms so
CLAUDE_CODE_OAUTH_TOKEN is only passed when the mention comes from a trusted
association.

permissions:
contents: read
pull-requests: read
issues: read
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and view the content around line 35
if [ -f ".github/workflows/claude.yml" ]; then
  echo "=== File exists. Checking line 35 and context ==="
  cat -n ".github/workflows/claude.yml" | sed -n '30,40p'
else
  echo "=== File does not exist. Searching for similar workflow files ==="
  find .github -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -10
fi

Repository: ESPresense/ESPresense-companion

Length of output: 548


🏁 Script executed:

# Search for all GitHub Actions usage in workflow files to check consistency
echo "=== Searching for all 'uses:' statements in workflow files ==="
rg "uses:" .github/workflows/ -n -A 0 2>/dev/null || echo "No matches found"

Repository: ESPresense/ESPresense-companion

Length of output: 1745


🌐 Web query:

GitHub Actions best practices pinning actions to commit SHA vs version tags security

💡 Result:

The best practice for GitHub Actions security is to pin actions to a full-length commit SHA rather than version tags. This makes the action immutable, preventing supply chain attacks where tags are moved or rewritten to point to malicious code, as tags can be updated or deleted if the repository is compromised [1][2]. Pinning to SHA mitigates risks because altering a specific commit requires a SHA-1 collision, which is computationally infeasible [1][3][4]. Version tags (e.g., @v4) are more convenient but less secure, as they are mutable and Dependabot alerts do not cover SHA-pinned actions [1][5]. Use tags only for trusted creators with a 'Verified creator' badge, but prefer SHA for high-risk third-party actions [1][3]. GitHub provides organization and repository policies to enforce SHA pinning, blocking workflows that use unpinned actions [1][6][7]. Example: uses: actions/checkout@692973e # v4.0.0 [3][8]. To implement: Verify SHA from the official repo (not forks), add version comments for maintenance, and use tools like Dependabot or scripts for updates [1][6][8][9]. This aligns with GitHub's security hardening guide and recent policy updates as of 2025 [1][7].

Citations:


Pin anthropics/claude-code-action to a commit SHA instead of @v1 for supply chain security.

Version tags like @v1 are mutable and can be rewritten or moved without PR visibility, exposing the workflow to upstream changes. Pinning to a specific commit SHA makes the action immutable and prevents tag-based attacks. GitHub's security hardening guide recommends this approach for all actions.

Suggested change
-        uses: anthropics/claude-code-action@v1
+        uses: anthropics/claude-code-action@<pinned_commit_sha> # v1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/claude.yml at line 35, Replace the mutable tag
"anthropics/claude-code-action@v1" with a specific commit SHA to pin the action
immutably; locate the workflow usage line that reads uses:
anthropics/claude-code-action@v1 and update it to uses:
anthropics/claude-code-action@<COMMIT_SHA> (obtain the desired commit SHA from
the action repository's commits/releases before updating) so the workflow
references an exact immutable revision.

with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
actions: read
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
# prompt: 'Update the pull request description to include a summary of changes.'

# Optional: Add claude_args to customize behavior and configuration
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options
# claude_args: '--allowed-tools Bash(gh pr *)'

Loading