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
201 changes: 201 additions & 0 deletions .github/CLAUDE_WORKFLOWS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# Claude Code GitHub Workflows Configuration

This repository uses two GitHub Actions workflows to integrate Claude Code:

1. **`claude.yml`** - Interactive Claude assistant triggered by `@claude` mentions
2. **`claude-code-review.yml`** - Automatic code review on pull requests

## Security

Both workflows include authorization checks to prevent unauthorized access to the `CLAUDE_CODE_OAUTH_TOKEN`. Only trusted contributors can trigger Claude workflows.

## Configuration Variables

Configure these workflows via **Settings β†’ Secrets and variables β†’ Actions β†’ Variables** in your repository.

### Shared Security Settings

#### `CLAUDE_AUTHORIZED_ROLES` (claude.yml)

- **Type:** JSON array
- **Default:** `["OWNER", "MEMBER", "COLLABORATOR"]`
- **Description:** GitHub author associations allowed to trigger `@claude` mentions
- **Example:** `["OWNER", "MEMBER"]` (restrict to owners and members only)
- **Security:** This is the primary security control. Only change if you understand the implications.

#### `CLAUDE_REVIEW_AUTHORIZED_ROLES` (claude-code-review.yml)

- **Type:** JSON array
- **Default:** `["OWNER", "MEMBER", "COLLABORATOR"]`
- **Description:** GitHub author associations allowed to trigger auto-reviews
- **Example:** `["OWNER"]` (only repository owners)

### Claude Assistant Settings (claude.yml)

#### `CLAUDE_MENTION_TRIGGER`

- **Type:** String
- **Default:** `@claude`
- **Description:** Text that triggers the Claude workflow
- **Example:** `@bot`, `@ai`, or any custom trigger word

#### `CLAUDE_CONCURRENCY_CANCEL`

- **Type:** String (boolean)
- **Default:** `false`
- **Description:** Whether to cancel in-progress Claude runs when new mention arrives
- **Values:** `true` or `false`
- **Use case:** Set to `true` if you want latest request to cancel previous ones

#### `CLAUDE_CUSTOM_PROMPT`

- **Type:** String (multiline supported)
- **Default:** Empty (Claude follows instructions from the comment)
- **Description:** Override default behavior with a custom prompt
- **Example:**
```
You are a helpful code assistant. Always:
- Reference CLAUDE.md for project standards
- Run validation before committing
- Be concise in responses
```

#### `CLAUDE_ALLOWED_TOOLS`

- **Type:** String
- **Default:** Empty (unrestricted access)
- **Description:** Restrict which tools Claude can use
- **Example:** `--allowed-tools "Bash(gh pr:*),Read,Edit"`
- **Security:** Restrict to specific commands to limit what Claude can do
- **See:** [Claude Code tool documentation](https://code.claude.com/docs/en/cli-reference)

### Code Review Settings (claude-code-review.yml)

#### `CLAUDE_REVIEW_CONCURRENCY_CANCEL`

- **Type:** String (boolean)
- **Default:** `false`
- **Description:** Whether to cancel in-progress reviews on new PR updates
- **Values:** `true` or `false`
- **Use case:** Set to `true` to cancel old review when PR is updated

#### `CLAUDE_REVIEW_CUSTOM_PROMPT`

- **Type:** String (multiline supported)
- **Default:** Pre-configured review prompt (see workflow file)
- **Description:** Custom review instructions for Claude
- **Example:**
```
Review this PR focusing on:
- TypeScript type safety
- Test coverage for new features
- Security vulnerabilities

Reference CLAUDE.md for coding standards.
Use gh pr comment to post your review.
```

#### `CLAUDE_REVIEW_ALLOWED_TOOLS`

- **Type:** String
- **Default:** `--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"`
- **Description:** Restrict which tools Claude can use during reviews
- **Security:** Default restricts to read-only gh commands + commenting
- **Example:** To make read-only: Remove `Bash(gh pr comment:*)` from the list

## Configuration Examples

### Example 1: Restrict to Repository Owners Only

```
CLAUDE_AUTHORIZED_ROLES = ["OWNER"]
CLAUDE_REVIEW_AUTHORIZED_ROLES = ["OWNER"]
```

### Example 2: Use Custom Trigger Word

```
CLAUDE_MENTION_TRIGGER = @bot
```

### Example 3: Cancel In-Progress Runs

```
CLAUDE_CONCURRENCY_CANCEL = true
CLAUDE_REVIEW_CONCURRENCY_CANCEL = true
```

### Example 4: Restrict Claude Tools (High Security)

```
CLAUDE_ALLOWED_TOOLS = --allowed-tools "Read,Grep,Glob,Bash(gh pr:*)"
CLAUDE_REVIEW_ALLOWED_TOOLS = --allowed-tools "Read,Grep,Glob,Bash(gh pr view:*),Bash(gh pr diff:*)"
```

### Example 5: Custom Review Prompt

```
CLAUDE_REVIEW_CUSTOM_PROMPT =
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}

Focus your review on:
1. Code matches docs/code/typescript.md standards
2. All changes have test coverage
3. No security vulnerabilities (SQL injection, XSS, etc.)
4. Performance implications

Reference CLAUDE.md for full project context.
Post review using: gh pr comment $PR_NUMBER --body "..."
```

## How to Set Variables

1. Go to your repository on GitHub
2. Click **Settings** β†’ **Secrets and variables** β†’ **Actions**
3. Click the **Variables** tab
4. Click **New repository variable**
5. Enter the variable name (e.g., `CLAUDE_AUTHORIZED_ROLES`)
6. Enter the value
7. Click **Add variable**

## Testing Configuration Changes

After changing variables, test by:

1. **For `claude.yml`:** Create a test issue or PR and mention your trigger word (e.g., `@claude`)
2. **For `claude-code-review.yml`:** Open a new PR or push to an existing PR

Check the **Actions** tab to see if workflows triggered correctly.

## Security Best Practices

1. **Always configure `CLAUDE_AUTHORIZED_ROLES`** - Never allow `CONTRIBUTOR` or `FIRST_TIME_CONTRIBUTOR`
2. **Restrict `CLAUDE_ALLOWED_TOOLS`** - Only give Claude the tools it needs
3. **Review workflow logs** - Periodically check Actions logs for suspicious activity
4. **Rotate tokens** - If you suspect token compromise, regenerate `CLAUDE_CODE_OAUTH_TOKEN`
5. **Use concurrency controls** - Prevents workflow spam attacks

## Troubleshooting

### Claude isn't responding to mentions

- Check that your GitHub author association matches `CLAUDE_AUTHORIZED_ROLES`
- Verify the trigger word matches `CLAUDE_MENTION_TRIGGER`
- Check workflow logs in the Actions tab for errors

### Reviews aren't running automatically

- Confirm PR author's association matches `CLAUDE_REVIEW_AUTHORIZED_ROLES`
- Check if workflow is enabled in **Settings β†’ Actions**
- Look for workflow runs in the Actions tab

### "Unrecognized named-value" warnings in IDE

These are expected linter warnings. Variables are resolved at runtime by GitHub Actions.

## Additional Resources

- [Claude Code Documentation](https://code.claude.com/docs)
- [GitHub Actions Variables](https://docs.github.com/en/actions/learn-github-actions/variables)
- [GitHub author_association values](https://docs.github.com/en/graphql/reference/enums#commentauthorassociation)
66 changes: 44 additions & 22 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
name: Claude Code Review

# Configuration via GitHub Actions Variables (Settings > Secrets and variables > Actions > Variables):
# - CLAUDE_REVIEW_AUTHORIZED_ROLES: JSON array of roles allowed (default: ["OWNER", "MEMBER", "COLLABORATOR"])
# - CLAUDE_REVIEW_CONCURRENCY_CANCEL: Cancel in-progress reviews (default: false)
# - CLAUDE_REVIEW_ALLOWED_TOOLS: Restrict tool access (default: gh commands only)
# - CLAUDE_REVIEW_CUSTOM_PROMPT: Optional custom review prompt

on:
pull_request:
types: [opened, synchronize]
Expand All @@ -12,11 +18,12 @@ on:

jobs:
claude-review:
# Optional: Filter by PR author
# if: |
# github.event.pull_request.user.login == 'external-contributor' ||
# github.event.pull_request.user.login == 'new-developer' ||
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
concurrency:
group: claude-review-${{ github.event.pull_request.number }}
cancel-in-progress: ${{ vars.CLAUDE_REVIEW_CONCURRENCY_CANCEL == 'true' }}
# Only run for trusted contributors (configurable via CLAUDE_REVIEW_AUTHORIZED_ROLES)
if: |
contains(fromJSON(vars.CLAUDE_REVIEW_AUTHORIZED_ROLES || '["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.pull_request.author_association)

runs-on: ubuntu-latest
permissions:
Expand All @@ -31,27 +38,42 @@ jobs:
with:
fetch-depth: 1

# Set default prompt if custom one not provided
- name: Set review prompt
id: set-prompt
run: |
if [ -n "${{ vars.CLAUDE_REVIEW_CUSTOM_PROMPT }}" ]; then
echo "prompt<<EOF" >> $GITHUB_OUTPUT
echo "${{ vars.CLAUDE_REVIEW_CUSTOM_PROMPT }}" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
else
echo "prompt<<EOF" >> $GITHUB_OUTPUT
cat <<'PROMPT_EOF' >> $GITHUB_OUTPUT
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}

Please review this pull request and provide feedback on:
- Code quality and best practices
- Potential bugs or issues
- Performance considerations
- Security concerns
- Test coverage

Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback.

Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.
PROMPT_EOF
echo "EOF" >> $GITHUB_OUTPUT
fi

- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}

Please review this pull request and provide feedback on:
- Code quality and best practices
- Potential bugs or issues
- Performance considerations
- Security concerns
- Test coverage

Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback.

Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.
prompt: ${{ steps.set-prompt.outputs.prompt }}

# Tool restrictions (configurable via CLAUDE_REVIEW_ALLOWED_TOOLS variable)
# Default: Only gh commands for reading and commenting
# 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 issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'

claude_args: ${{ vars.CLAUDE_REVIEW_ALLOWED_TOOLS || '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"' }}
37 changes: 27 additions & 10 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
name: Claude Code

# Configuration via GitHub Actions Variables (Settings > Secrets and variables > Actions > Variables):
# - CLAUDE_AUTHORIZED_ROLES: JSON array of roles allowed to trigger (default: ["OWNER", "MEMBER", "COLLABORATOR"])
# - CLAUDE_MENTION_TRIGGER: Text to trigger workflow (default: @claude)
# - CLAUDE_CONCURRENCY_CANCEL: Cancel in-progress runs (default: false)
# - CLAUDE_ALLOWED_TOOLS: Restrict tool access (default: unrestricted)
# - CLAUDE_CUSTOM_PROMPT: Optional custom prompt to override default behavior

on:
issue_comment:
types: [created]
Expand All @@ -12,11 +19,20 @@ on:

jobs:
claude:
concurrency:
group: claude-${{ github.event.issue.number || github.event.pull_request.number }}
cancel-in-progress: ${{ vars.CLAUDE_CONCURRENCY_CANCEL == 'true' }}
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, vars.CLAUDE_MENTION_TRIGGER || '@claude') &&
contains(fromJSON(vars.CLAUDE_AUTHORIZED_ROLES || '["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, vars.CLAUDE_MENTION_TRIGGER || '@claude') &&
contains(fromJSON(vars.CLAUDE_AUTHORIZED_ROLES || '["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, vars.CLAUDE_MENTION_TRIGGER || '@claude') &&
contains(fromJSON(vars.CLAUDE_AUTHORIZED_ROLES || '["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, vars.CLAUDE_MENTION_TRIGGER || '@claude') || contains(github.event.issue.title, vars.CLAUDE_MENTION_TRIGGER || '@claude')) &&
contains(fromJSON(vars.CLAUDE_AUTHORIZED_ROLES || '["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association))
)
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -36,15 +52,16 @@ jobs:
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

# This is an optional setting that allows Claude to read CI results on PRs
# Allow 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.'
# Custom prompt (configurable via CLAUDE_CUSTOM_PROMPT variable)
# If not set, Claude will perform instructions from the comment that tagged it
prompt: ${{ vars.CLAUDE_CUSTOM_PROMPT || '' }}

# Optional: Add claude_args to customize behavior and configuration
# Tool restrictions (configurable via CLAUDE_ALLOWED_TOOLS variable)
# 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:*)'

# Example: '--allowed-tools "Bash(gh pr:*)"'
claude_args: ${{ vars.CLAUDE_ALLOWED_TOOLS || '' }}
Loading