Compare commits

...

12 Commits

Author SHA1 Message Date
Boris Cherny
80ceacaa78 Re-add log-issue-events workflow with security fix
Re-implements the workflow removed in #5919, but with proper security:
- All GitHub event data is now passed via environment variables
- No direct templating of values into shell commands
- Prevents remote code execution through malicious issue titles
- Still escapes quotes in JSON payload for proper formatting

This fixes the security vulnerability while maintaining the functionality
of logging issue creation events to Statsig.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-18 09:56:56 -07:00
Chris Lloyd
4e63568abd Merge pull request #5919 from anthropics/chrislloyd/8a49b1
Remove log-issue-events workflow
2025-08-16 07:32:25 -07:00
Chris Lloyd
5d0b81ae41 Remove log-issue-events workflow 2025-08-16 07:26:53 -07:00
GitHub Actions
b1751f2e86 chore: Update CHANGELOG.md 2025-08-16 00:11:04 +00:00
Boris Cherny
fc8c10995f Merge pull request #5858 from anthropics/boris/vreg
fix: update auto-close-duplicates workflow permissions to write
2025-08-15 10:57:02 -07:00
Boris Cherny
01fb7af5b3 fix: update auto-close-duplicates workflow permissions to write
Change issues permission from read to write to fix 403 Forbidden
errors when attempting to close duplicate issues.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-15 10:55:50 -07:00
Boris Cherny
afb0fc9156 Merge pull request #5802 from anthropics/boris/jymy
fix: improve duplicate issue number extraction in auto-close script
2025-08-14 16:38:49 -07:00
Boris Cherny
370a97d939 fix: improve duplicate issue number extraction in auto-close script
The extractDuplicateIssueNumber function now handles both #123 format
and full GitHub issue URLs like https://github.com/owner/repo/issues/123.
This fixes the "could not extract duplicate issue number from comment"
errors that were occurring when the script encountered URL-formatted
issue references in duplicate detection comments.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-14 16:37:46 -07:00
GitHub Actions
f54569efd2 chore: Update CHANGELOG.md 2025-08-14 20:13:16 +00:00
GitHub Actions
d8cf5a874c chore: Update CHANGELOG.md 2025-08-14 16:59:55 +00:00
GitHub Actions
e499db6e9e chore: Update CHANGELOG.md 2025-08-11 23:43:35 +00:00
Boris Cherny
5300e12135 Merge pull request #5569 from anthropics/boris/limc
Consolidate GitHub issue closure events
2025-08-11 16:07:18 -07:00
4 changed files with 69 additions and 162 deletions

View File

@@ -11,7 +11,7 @@ jobs:
timeout-minutes: 10
permissions:
contents: read
issues: read
issues: write
steps:
- name: Checkout repository

View File

@@ -1,176 +1,40 @@
name: Log GitHub Issue Events
name: Log Issue Events to Statsig
on:
issues:
types: [opened, closed]
types: [opened]
jobs:
log-issue-created:
if: github.event.action == 'opened'
log-to-statsig:
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
issues: read
steps:
- name: Log issue creation to Statsig
env:
STATSIG_API_KEY: ${{ secrets.STATSIG_API_KEY }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
REPO: ${{ github.repository }}
ISSUE_TITLE: ${{ github.event.issue.title }}
AUTHOR: ${{ github.event.issue.user.login }}
CREATED_AT: ${{ github.event.issue.created_at }}
run: |
ISSUE_NUMBER=${{ github.event.issue.number }}
REPO=${{ github.repository }}
ISSUE_TITLE=$(echo '${{ github.event.issue.title }}' | sed "s/'/'\\\\''/g")
AUTHOR="${{ github.event.issue.user.login }}"
CREATED_AT="${{ github.event.issue.created_at }}"
# All values are now safely passed via environment variables
# No direct templating in the shell script to prevent injection attacks
if [ -z "$STATSIG_API_KEY" ]; then
echo "STATSIG_API_KEY not found, skipping Statsig logging"
exit 0
fi
# Prepare the event payload
EVENT_PAYLOAD=$(jq -n \
--arg issue_number "$ISSUE_NUMBER" \
--arg repo "$REPO" \
--arg title "$ISSUE_TITLE" \
--arg author "$AUTHOR" \
--arg created_at "$CREATED_AT" \
'{
events: [{
eventName: "github_issue_created",
value: 1,
metadata: {
repository: $repo,
issue_number: ($issue_number | tonumber),
issue_title: $title,
issue_author: $author,
created_at: $created_at
},
time: (now | floor | tostring)
}]
}')
# Send to Statsig API
echo "Logging issue creation to Statsig for issue #${ISSUE_NUMBER}"
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST https://events.statsigapi.net/v1/log_event \
curl -X POST "https://events.statsigapi.net/v1/log_event" \
-H "Content-Type: application/json" \
-H "STATSIG-API-KEY: ${STATSIG_API_KEY}" \
-d "$EVENT_PAYLOAD")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | head -n-1)
if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 202 ]; then
echo "Successfully logged issue creation for issue #${ISSUE_NUMBER}"
else
echo "Failed to log issue creation for issue #${ISSUE_NUMBER}. HTTP ${HTTP_CODE}: ${BODY}"
fi
log-issue-closed:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
issues: read
steps:
- name: Log issue closure to Statsig
env:
STATSIG_API_KEY: ${{ secrets.STATSIG_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
ISSUE_NUMBER=${{ github.event.issue.number }}
REPO=${{ github.repository }}
ISSUE_TITLE=$(echo '${{ github.event.issue.title }}' | sed "s/'/'\\\\''/g")
CLOSED_BY="${{ github.event.issue.closed_by.login }}"
CLOSED_AT="${{ github.event.issue.closed_at }}"
STATE_REASON="${{ github.event.issue.state_reason }}"
if [ -z "$STATSIG_API_KEY" ]; then
echo "STATSIG_API_KEY not found, skipping Statsig logging"
exit 0
fi
# Get additional issue data via GitHub API
echo "Fetching additional issue data for #${ISSUE_NUMBER}"
ISSUE_DATA=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${REPO}/issues/${ISSUE_NUMBER}")
COMMENTS_COUNT=$(echo "$ISSUE_DATA" | jq -r '.comments')
# Get reactions data
REACTIONS_DATA=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${REPO}/issues/${ISSUE_NUMBER}/reactions")
REACTIONS_COUNT=$(echo "$REACTIONS_DATA" | jq '. | length')
# Check if issue was closed automatically (by checking if closed_by is a bot)
CLOSED_AUTOMATICALLY="false"
if [[ "$CLOSED_BY" == *"[bot]"* ]]; then
CLOSED_AUTOMATICALLY="true"
fi
# Check if closed as duplicate by state_reason
CLOSED_AS_DUPLICATE="false"
if [ "$STATE_REASON" = "duplicate" ]; then
CLOSED_AS_DUPLICATE="true"
fi
# Prepare the event payload
EVENT_PAYLOAD=$(jq -n \
--arg issue_number "$ISSUE_NUMBER" \
--arg repo "$REPO" \
--arg title "$ISSUE_TITLE" \
--arg closed_by "$CLOSED_BY" \
--arg closed_at "$CLOSED_AT" \
--arg state_reason "$STATE_REASON" \
--arg comments_count "$COMMENTS_COUNT" \
--arg reactions_count "$REACTIONS_COUNT" \
--arg closed_automatically "$CLOSED_AUTOMATICALLY" \
--arg closed_as_duplicate "$CLOSED_AS_DUPLICATE" \
'{
events: [{
eventName: "github_issue_closed",
value: 1,
metadata: {
repository: $repo,
issue_number: ($issue_number | tonumber),
issue_title: $title,
closed_by: $closed_by,
closed_at: $closed_at,
state_reason: $state_reason,
comments_count: ($comments_count | tonumber),
reactions_count: ($reactions_count | tonumber),
closed_automatically: ($closed_automatically | test("true")),
closed_as_duplicate: ($closed_as_duplicate | test("true"))
-H "statsig-api-key: $STATSIG_API_KEY" \
-d '{
"events": [{
"eventName": "github_issue_created",
"metadata": {
"issue_number": "'"$ISSUE_NUMBER"'",
"repository": "'"$REPO"'",
"title": "'"$(echo "$ISSUE_TITLE" | sed "s/\"/\\\\\"/g")"'",
"author": "'"$AUTHOR"'",
"created_at": "'"$CREATED_AT"'"
},
time: (now | floor | tostring)
"time": '"$(date +%s)000"'
}]
}')
# Send to Statsig API
echo "Logging issue closure to Statsig for issue #${ISSUE_NUMBER}"
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST https://events.statsigapi.net/v1/log_event \
-H "Content-Type: application/json" \
-H "STATSIG-API-KEY: ${STATSIG_API_KEY}" \
-d "$EVENT_PAYLOAD")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | head -n-1)
if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 202 ]; then
echo "Successfully logged issue closure for issue #${ISSUE_NUMBER}"
echo "Closed by: $CLOSED_BY"
echo "Comments: $COMMENTS_COUNT"
echo "Reactions: $REACTIONS_COUNT"
echo "Closed automatically: $CLOSED_AUTOMATICALLY"
echo "Closed as duplicate: $CLOSED_AS_DUPLICATE"
else
echo "Failed to log issue closure for issue #${ISSUE_NUMBER}. HTTP ${HTTP_CODE}: ${BODY}"
fi
}'

View File

@@ -1,5 +1,37 @@
# Changelog
## 1.0.82
- SDK: Add request cancellation support
- SDK: New additionalDirectories option to search custom paths, improved slash command processing
- Settings: Validation prevents invalid fields in .claude/settings.json files
- MCP: Improve tool name consistency
- Bash: Fix crash when Claude tries to automatically read large files
## 1.0.81
- Released output styles, including new built-in educational output styles "Explanatory" and "Learning". Docs: https://docs.anthropic.com/en/docs/claude-code/output-styles
- Agents: Fix custom agent loading when agent files are unparsable
## 1.0.80
- UI improvements: Fix text contrast for custom subagent colors and spinner rendering issues
## 1.0.77
- Bash tool: Fix heredoc and multiline string escaping, improve stderr redirection handling
- SDK: Add session support and permission denial tracking
- Fix token limit errors in conversation summarization
- Opus Plan Mode: New setting in `/model` to run Opus only in plan mode, Sonnet otherwise
## 1.0.73
- MCP: Support multiple config files with `--mcp-config file1.json file2.json`
- MCP: Press Esc to cancel OAuth authentication flows
- Bash: Improved command validation and reduced false security warnings
- UI: Enhanced spinner animations and status line visual hierarchy
- Linux: Added support for Alpine and musl-based distributions (requires separate ripgrep installation)
## 1.0.72
- Ask permissions: have Claude Code always ask for confirmation to use specific tools with /permissions

View File

@@ -47,8 +47,19 @@ async function githubRequest<T>(endpoint: string, token: string, method: string
}
function extractDuplicateIssueNumber(commentBody: string): number | null {
const match = commentBody.match(/#(\d+)/);
return match ? parseInt(match[1], 10) : null;
// Try to match #123 format first
let match = commentBody.match(/#(\d+)/);
if (match) {
return parseInt(match[1], 10);
}
// Try to match GitHub issue URL format: https://github.com/owner/repo/issues/123
match = commentBody.match(/github\.com\/[^\/]+\/[^\/]+\/issues\/(\d+)/);
if (match) {
return parseInt(match[1], 10);
}
return null;
}