diff --git a/.github/workflows/claude-full.yml b/.github/workflows/claude-full.yml index 0da4e3b..e444b47 100644 --- a/.github/workflows/claude-full.yml +++ b/.github/workflows/claude-full.yml @@ -26,6 +26,8 @@ on: secrets: ANTHROPIC_API_KEY: required: true + PERSONAL_ACCESS_TOKEN: + required: false jobs: # Handle issue analysis comments @@ -46,16 +48,22 @@ jobs: id: issue run: | ISSUE_NUMBER="${{ github.event.issue.number }}" - FEEDBACK="${{ github.event.comment.body }}" + # Use single quotes to prevent Bash from interpreting special characters + FEEDBACK='${{ github.event.comment.body }}' + COMMENT_AUTHOR="${{ github.event.comment.user.login }}" # Remove the "claude:" prefix FEEDBACK="${FEEDBACK#claude:}" # Remove newlines from feedback to prevent GitHub Actions output issues FEEDBACK_CLEANED="$(echo "$FEEDBACK" | tr '\n' ' ')" echo "number=${ISSUE_NUMBER}" >> $GITHUB_OUTPUT - echo "feedback=${FEEDBACK_CLEANED}" >> $GITHUB_OUTPUT + # Use EOF to properly handle special characters in GITHUB_OUTPUT + echo "feedback<> $GITHUB_OUTPUT + echo "$FEEDBACK_CLEANED" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "comment_author=${COMMENT_AUTHOR}" >> $GITHUB_OUTPUT - name: Process with Claude Code for issue analysis - uses: fractureinc/claude-code-github-action@v0.5.5 + uses: basicmachines-co/claude-code-github-action@v0.11.0 with: mode: 'issue-analyze' issue-number: ${{ steps.issue.outputs.number }} @@ -65,6 +73,8 @@ jobs: debug-mode: ${{ inputs.debug-mode || 'false' }} anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} github-token: ${{ github.token }} + personal-access-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + comment-author: ${{ steps.issue.outputs.comment_author }} - name: Upload claude output artifacts if: always() @@ -101,16 +111,22 @@ jobs: id: issue run: | ISSUE_NUMBER="${{ github.event.issue.number }}" - FEEDBACK="${{ github.event.comment.body }}" + # Use single quotes to prevent Bash from interpreting special characters + FEEDBACK='${{ github.event.comment.body }}' + COMMENT_AUTHOR="${{ github.event.comment.user.login }}" # Remove the "claude-fix:" prefix FEEDBACK="${FEEDBACK#claude-fix:}" # Remove newlines from feedback to prevent GitHub Actions output issues FEEDBACK_CLEANED="$(echo "$FEEDBACK" | tr '\n' ' ')" echo "number=${ISSUE_NUMBER}" >> $GITHUB_OUTPUT - echo "feedback=${FEEDBACK_CLEANED}" >> $GITHUB_OUTPUT + # Use EOF to properly handle special characters in GITHUB_OUTPUT + echo "feedback<> $GITHUB_OUTPUT + echo "$FEEDBACK_CLEANED" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "comment_author=${COMMENT_AUTHOR}" >> $GITHUB_OUTPUT - name: Process with Claude Code for issue fix - uses: fractureinc/claude-code-github-action@v0.5.5 + uses: basicmachines-co/claude-code-github-action@v0.11.0 with: mode: 'issue-fix' issue-number: ${{ steps.issue.outputs.number }} @@ -122,6 +138,8 @@ jobs: feedback: ${{ steps.issue.outputs.feedback }} anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} github-token: ${{ github.token }} + personal-access-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + comment-author: ${{ steps.issue.outputs.comment_author }} - name: Upload claude output artifacts if: always() @@ -148,16 +166,20 @@ jobs: id: pr run: | PR_NUMBER="${{ github.event.issue.number }}" - FEEDBACK="${{ github.event.comment.body }}" + # Use single quotes to prevent Bash from interpreting special characters + FEEDBACK='${{ github.event.comment.body }}' # Remove the "claude:" prefix FEEDBACK="${FEEDBACK#claude:}" # Remove newlines from feedback to prevent GitHub Actions output issues FEEDBACK_CLEANED="$(echo "$FEEDBACK" | tr '\n' ' ')" echo "number=${PR_NUMBER}" >> $GITHUB_OUTPUT - echo "feedback=${FEEDBACK_CLEANED}" >> $GITHUB_OUTPUT + # Use EOF to properly handle special characters in GITHUB_OUTPUT + echo "feedback<> $GITHUB_OUTPUT + echo "$FEEDBACK_CLEANED" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT - name: Process with Claude Code - uses: fractureinc/claude-code-github-action@v0.5.5 + uses: basicmachines-co/claude-code-github-action@v0.11.0 with: mode: 'review' pr-number: ${{ steps.pr.outputs.number }} @@ -183,16 +205,20 @@ jobs: id: pr run: | PR_NUMBER="${{ github.event.issue.number }}" - FEEDBACK="${{ github.event.comment.body }}" + # Use single quotes to prevent Bash from interpreting special characters + FEEDBACK='${{ github.event.comment.body }}' # Remove the "claude-suggest:" prefix FEEDBACK="${FEEDBACK#claude-suggest:}" # Remove newlines from feedback to prevent GitHub Actions output issues FEEDBACK_CLEANED="$(echo "$FEEDBACK" | tr '\n' ' ')" echo "number=${PR_NUMBER}" >> $GITHUB_OUTPUT - echo "feedback=${FEEDBACK_CLEANED}" >> $GITHUB_OUTPUT + # Use EOF to properly handle special characters in GITHUB_OUTPUT + echo "feedback<> $GITHUB_OUTPUT + echo "$FEEDBACK_CLEANED" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT - name: Process with Claude Code Suggestions - uses: fractureinc/claude-code-github-action@v0.5.5 + uses: basicmachines-co/claude-code-github-action@v0.11.0 with: mode: 'suggest' pr-number: ${{ steps.pr.outputs.number }} @@ -220,7 +246,8 @@ jobs: id: details run: | PR_NUMBER="${{ github.event.pull_request.number }}" - FEEDBACK="${{ github.event.comment.body }}" + # Use single quotes to prevent Bash from interpreting special characters + FEEDBACK='${{ github.event.comment.body }}' # Remove the "claude:" prefix FEEDBACK="${FEEDBACK#claude:}" COMMENT_ID="${{ github.event.comment.id }}" @@ -230,14 +257,17 @@ jobs: # Remove newlines from feedback to prevent GitHub Actions output issues FEEDBACK_CLEANED="$(echo "$FEEDBACK" | tr '\n' ' ')" echo "number=${PR_NUMBER}" >> $GITHUB_OUTPUT - echo "feedback=${FEEDBACK_CLEANED}" >> $GITHUB_OUTPUT + # Use EOF to properly handle special characters in GITHUB_OUTPUT + echo "feedback<> $GITHUB_OUTPUT + echo "$FEEDBACK_CLEANED" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT echo "comment_id=${COMMENT_ID}" >> $GITHUB_OUTPUT echo "file_path=${FILE_PATH}" >> $GITHUB_OUTPUT echo "line=${LINE}" >> $GITHUB_OUTPUT - name: Process with Claude Code for code review comment - uses: fractureinc/claude-code-github-action@v0.5.5 + uses: basicmachines-co/claude-code-github-action@v0.11.0 with: mode: 'review' pr-number: ${{ steps.details.outputs.number }} @@ -263,7 +293,8 @@ jobs: id: details run: | PR_NUMBER="${{ github.event.pull_request.number }}" - FEEDBACK="${{ github.event.comment.body }}" + # Use single quotes to prevent Bash from interpreting special characters + FEEDBACK='${{ github.event.comment.body }}' # Remove the "claude-suggest:" prefix FEEDBACK="${FEEDBACK#claude-suggest:}" COMMENT_ID="${{ github.event.comment.id }}" @@ -273,14 +304,17 @@ jobs: # Remove newlines from feedback to prevent GitHub Actions output issues FEEDBACK_CLEANED="$(echo "$FEEDBACK" | tr '\n' ' ')" echo "number=${PR_NUMBER}" >> $GITHUB_OUTPUT - echo "feedback=${FEEDBACK_CLEANED}" >> $GITHUB_OUTPUT + # Use EOF to properly handle special characters in GITHUB_OUTPUT + echo "feedback<> $GITHUB_OUTPUT + echo "$FEEDBACK_CLEANED" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT echo "comment_id=${COMMENT_ID}" >> $GITHUB_OUTPUT echo "file_path=${FILE_PATH}" >> $GITHUB_OUTPUT echo "line=${LINE}" >> $GITHUB_OUTPUT - name: Process with Claude Code Suggestions for code review - uses: fractureinc/claude-code-github-action@v0.5.5 + uses: basicmachines-co/claude-code-github-action@v0.11.0 with: mode: 'suggest-review' pr-number: ${{ steps.details.outputs.number }} diff --git a/.github/workflows/claude-label-fix.yml b/.github/workflows/claude-label-fix.yml index 8ce7a15..9feaeca 100644 --- a/.github/workflows/claude-label-fix.yml +++ b/.github/workflows/claude-label-fix.yml @@ -47,7 +47,7 @@ jobs: git config --global user.email "claude-bot@example.com" - name: Process issue with Claude Code - uses: fractureinc/claude-code-github-action@v0.5.5 + uses: basicmachines-co/claude-code-github-action@v0.11.0 with: mode: 'issue-fix' issue-number: ${{ github.event.issue.number }} diff --git a/.github/workflows/example-minimal.yml b/.github/workflows/example-minimal.yml index 5dd7365..d03c2e9 100644 --- a/.github/workflows/example-minimal.yml +++ b/.github/workflows/example-minimal.yml @@ -9,7 +9,7 @@ on: # This demonstrates how to use the reusable workflow for comment-based interactions jobs: claude-integration: - uses: fractureinc/claude-code-github-action/.github/workflows/claude-full.yml@v0.5.6 + uses: basicmachines-co/claude-code-github-action/.github/workflows/claude-full.yml@v0.11.0 with: # Optional customizations: issue-label: 'claude-fix' # The label used to trigger issue fixes diff --git a/README.md b/README.md index 1a0aa3c..c38e0d5 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This GitHub Action integrates Claude Code in your GitHub workflows, enabling AI- ### 1. Add Claude to Your Repository -Create two simple workflow files to integrate Claude with your repository: +Create a workflow file to integrate Claude with your repository: **File: `.github/workflows/claude-code.yml`** ```yaml @@ -30,7 +30,7 @@ on: jobs: claude-integration: - uses: fractureinc/claude-code-github-action/.github/workflows/claude-full.yml@v0.5.6 + uses: basicmachines-co/claude-code-github-action/.github/workflows/claude-full.yml@v0.10.0 with: issue-label: 'claude-fix' # Optional: customize the trigger label secrets: @@ -47,7 +47,7 @@ on: jobs: claude-label-fix: - uses: fractureinc/claude-code-github-action/.github/workflows/claude-label-fix.yml@v0.5.6 + uses: basicmachines-co/claude-code-github-action/.github/workflows/claude-label-fix.yml@v0.10.0 with: issue-label: 'claude-fix' # Must match your chosen label secrets: @@ -97,15 +97,18 @@ The reusable workflows support several configuration options: ```yaml jobs: claude-integration: - uses: fractureinc/claude-code-github-action/.github/workflows/claude-full.yml@v0.5.6 + uses: basicmachines-co/claude-code-github-action/.github/workflows/claude-full.yml@v0.10.0 with: # All parameters are optional with sensible defaults - issue-label: 'claude-fix' # Label that triggers issue fixes - branch-prefix: 'fix' # Prefix for branches created by fixes - debug-mode: false # Enable verbose logging - strict-mode: true # When false, allows Claude to add improvements + issue-label: 'claude-fix' # Label that triggers issue fixes + branch-prefix: 'fix' # Prefix for branches created by fixes + require-org-membership: true # Only process issues from org members + organization: 'my-org' # Organization to check membership against + debug-mode: false # Enable verbose logging + strict-mode: true # When false, allows Claude to add improvements secrets: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # Optional: For commit attribution ``` ### Label-Based Integration (`claude-label-fix.yml`) @@ -113,14 +116,17 @@ jobs: ```yaml jobs: claude-label-fix: - uses: fractureinc/claude-code-github-action/.github/workflows/claude-label-fix.yml@v0.5.6 + uses: basicmachines-co/claude-code-github-action/.github/workflows/claude-label-fix.yml@v0.10.0 with: # All parameters are optional with sensible defaults - issue-label: 'claude-fix' # Must match the label you're using - branch-prefix: 'fix' # Prefix for branches created by fixes - debug-mode: false # Enable verbose logging + issue-label: 'claude-fix' # Must match the label you're using + branch-prefix: 'fix' # Prefix for branches created by fixes + require-org-membership: true # Only process issues from org members + organization: 'my-org' # Organization to check membership against + debug-mode: false # Enable verbose logging secrets: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # Optional: For commit attribution ``` Only repo maintainers with write access can add labels, providing security control over which issues Claude will fix. @@ -145,6 +151,9 @@ When using our reusable workflows, you only need to configure a few key options: |-----------|-------------|---------|---------| | `issue-label` | Label that triggers issue fixes | `claude-fix` | Both workflows | | `branch-prefix` | Prefix for branches created by fixes | `fix` | Both workflows | +| `require-org-membership` | Require the comment author to be a public member of the organization | `true` | Both workflows | +| `organization` | Organization name to check membership against | Repository owner | Both workflows | +| `personal-access-token` | Token for commits to override the default GitHub token | None | Both workflows | | `debug-mode` | Enable verbose logging | `false` | Both workflows | | `strict-mode` | Controls whether Claude adds improvements beyond what's requested | `true` | Comment workflow only | @@ -152,7 +161,7 @@ All parameters are optional and have sensible defaults. ## Enhanced Context for Claude -With version 0.5.6, Claude now receives complete context for your PRs and issues, including: +With version 0.10.0, Claude receives complete context for your PRs and issues, including: - PR metadata (title, description, branch info) - Issue details (title, description, labels) @@ -211,7 +220,29 @@ permissions: - Only users with appropriate GitHub permissions can trigger Claude Code actions - For issue fixes, using the label-based approach gives you more control over who can trigger code changes - The `strict-mode` parameter limits Claude to only making requested changes +- The `require-org-membership` option ensures only organization members can use Claude for issues +- Using a personal access token for commits ensures proper attribution and bypasses CLA requirements + +### Organization Membership Visibility Requirement + +When using `require-org-membership: true` (which is the default), the GitHub user who triggers Claude (by commenting with `claude:` or `claude-fix:`) must be a **public** member of the organization. + +**Important:** By default, GitHub organization memberships are private, which means the API cannot verify your membership. To make your membership public: + +1. **Go to your organization page**: `https://github.com/your-organization-name` +2. **Click on the "People" tab** +3. **Find your username** in the member list +4. **Click on the "Private" dropdown** next to your name +5. **Select "Make public"** + +Alternatively, you can do this from your profile: +1. Go to your GitHub profile +2. Click on "Organizations" in the left sidebar +3. Find the organization in the list +4. Click the "Make public" button + +This allows the GitHub API to verify your organization membership when you use Claude Code action. ## License -MIT \ No newline at end of file +MIT diff --git a/action.yml b/action.yml index d941b0e..e304162 100644 --- a/action.yml +++ b/action.yml @@ -29,6 +29,13 @@ inputs: description: 'Label that triggers issue fix workflows' required: false default: 'claude-fix' + require-org-membership: + description: 'Whether to require the issue creator to be an organization member to process the issue' + required: false + default: 'true' + organization: + description: 'The GitHub organization name to check membership against (defaults to the repo owner)' + required: false debug-mode: description: 'Enable full debug mode with shell tracing and Claude debug output' required: false @@ -55,6 +62,12 @@ inputs: github-token: description: 'GitHub token for API access' required: true + personal-access-token: + description: 'Optional personal access token for commits, to override the default GitHub token' + required: false + comment-author: + description: 'The GitHub username of the person who made the comment' + required: false output-file: description: 'Path to write the output to (for direct mode)' required: false @@ -111,11 +124,11 @@ runs: shell: bash run: | chmod +x ${{ github.action_path }}/scripts/issue-fix-mode.sh - ${{ github.action_path }}/scripts/issue-fix-mode.sh "${{ inputs.issue-number }}" "${{ inputs.repo-owner }}" "${{ inputs.repo-name }}" "${{ inputs.branch-prefix }}" "${{ inputs.anthropic-api-key }}" "${{ inputs.github-token }}" "${{ inputs.issue-label }}" "${{ inputs.debug-mode }}" "${{ inputs.feedback }}" + ${{ github.action_path }}/scripts/issue-fix-mode.sh "${{ inputs.issue-number }}" "${{ inputs.repo-owner }}" "${{ inputs.repo-name }}" "${{ inputs.branch-prefix }}" "${{ inputs.anthropic-api-key }}" "${{ inputs.github-token }}" "${{ inputs.issue-label }}" "${{ inputs.debug-mode }}" "${{ inputs.feedback }}" "${{ inputs.require-org-membership }}" "${{ inputs.organization }}" "${{ inputs.personal-access-token }}" "${{ inputs.comment-author }}" - name: Process Issue Analysis if: inputs.mode == 'issue-analyze' shell: bash run: | chmod +x ${{ github.action_path }}/scripts/issue-analyze-mode.sh - ${{ github.action_path }}/scripts/issue-analyze-mode.sh "${{ inputs.issue-number }}" "${{ inputs.repo-owner }}" "${{ inputs.repo-name }}" "${{ inputs.anthropic-api-key }}" "${{ inputs.github-token }}" "${{ inputs.debug-mode }}" "${{ inputs.feedback }}" \ No newline at end of file + ${{ github.action_path }}/scripts/issue-analyze-mode.sh "${{ inputs.issue-number }}" "${{ inputs.repo-owner }}" "${{ inputs.repo-name }}" "${{ inputs.anthropic-api-key }}" "${{ inputs.github-token }}" "${{ inputs.debug-mode }}" "${{ inputs.feedback }}" "${{ inputs.require-org-membership }}" "${{ inputs.organization }}" "${{ inputs.personal-access-token }}" "${{ inputs.comment-author }}" \ No newline at end of file diff --git a/package.json b/package.json index a53c65a..d515301 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-code-github-action", - "version": "0.5.6", + "version": "0.11.0", "description": "GitHub action for Claude Code Integration in PR comments, reviews, inline code suggestions, and issue-based fixes", "main": "index.js", "scripts": { diff --git a/scripts/issue-analyze-mode.sh b/scripts/issue-analyze-mode.sh index 4fab8cf..0a0b4d4 100755 --- a/scripts/issue-analyze-mode.sh +++ b/scripts/issue-analyze-mode.sh @@ -10,6 +10,10 @@ ANTHROPIC_API_KEY=$4 GITHUB_TOKEN=$5 DEBUG_MODE=${6:-"false"} FEEDBACK=$7 +REQUIRE_ORG_MEMBERSHIP=${8:-"true"} +ORGANIZATION=${9:-$REPO_OWNER} +PERSONAL_ACCESS_TOKEN=${10:-$GITHUB_TOKEN} +COMMENT_AUTHOR=${11:-""} # Enable debug mode if requested if [[ "$DEBUG_MODE" == "true" ]]; then @@ -92,7 +96,7 @@ else FULL_REPO="$REPO_OWNER/$REPO_NAME" fi echo "Using repository: $FULL_REPO" -if ! ISSUE_DETAILS=$(gh issue view $ISSUE_NUMBER --repo "$FULL_REPO" --json title,body,labels); then +if ! ISSUE_DETAILS=$(gh issue view $ISSUE_NUMBER --repo "$FULL_REPO" --json title,body,labels,author); then echo "Error fetching issue details" exit 1 fi @@ -101,6 +105,50 @@ fi ISSUE_TITLE=$(echo "$ISSUE_DETAILS" | jq -r '.title') ISSUE_BODY=$(echo "$ISSUE_DETAILS" | jq -r '.body') ISSUE_LABELS=$(echo "$ISSUE_DETAILS" | jq -r '.labels[].name' | tr '\n' ',' | sed 's/,$//' || echo "none") +ISSUE_AUTHOR=$(echo "$ISSUE_DETAILS" | jq -r '.author.login') + +# Check if user is a member of the organization if required +if [[ "$REQUIRE_ORG_MEMBERSHIP" == "true" ]]; then + # Use the comment author for the org membership check if provided, otherwise fall back to issue author + CHECK_USER="${COMMENT_AUTHOR:-$ISSUE_AUTHOR}" + echo "Checking if $CHECK_USER is a member of organization $ORGANIZATION" + + # Debug output + echo "Comment Author: $COMMENT_AUTHOR" + echo "Issue Author: $ISSUE_AUTHOR" + echo "User being checked: $CHECK_USER" + + # Always use the GitHub token for org membership check + echo "Using GitHub Token for organization membership check" + ORG_CHECK=$(gh api -X GET /orgs/$ORGANIZATION/members/$CHECK_USER --silent -i || true) + + STATUS_CODE=$(echo "$ORG_CHECK" | head -n 1 | cut -d' ' -f2) + + if [[ "$STATUS_CODE" != "204" ]]; then + echo "User $CHECK_USER is not a member of organization $ORGANIZATION. Skipping Claude analysis." + + # Leave a comment on the issue explaining why the analysis is skipped + ISSUE_COMMENT=$(cat <