-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathaction.yml
More file actions
480 lines (392 loc) · 20.9 KB
/
Copy pathaction.yml
File metadata and controls
480 lines (392 loc) · 20.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
name: "Claude Auto Review"
description: "Automated code review using Claude AI with configurable project context"
author: "WalletConnect"
inputs:
anthropic_api_key:
description: "Anthropic API key for Claude access"
required: true
model:
description: "Claude model to use for reviews"
required: false
default: "claude-sonnet-4-6"
timeout_minutes:
description: "DEPRECATED: Accepted but ignored by v1 (no effect). Use job-level timeout-minutes instead."
required: false
custom_prompt:
description: "Complete custom prompt override. If provided, all other prompt-related inputs are ignored."
required: false
project_context:
description: "Additional project-specific context to help Claude understand your codebase"
required: false
comment_pr_findings:
description: "Post inline PR comments generated from findings.json"
required: false
default: "true"
force_breaking_changes_agent:
description: "Force breaking changes agent regardless of heuristic"
required: false
default: "false"
force_license_compliance_agent:
description: "Force license compliance agent regardless of heuristic"
required: false
default: "false"
force_data_classification_agent:
description: "Force data classification agent regardless of heuristic"
required: false
default: "false"
force_deduplication_agent:
description: "Force deduplication agent regardless of heuristic"
required: false
default: "false"
runs:
using: "composite"
steps:
- name: Determine if breaking changes agent should spawn
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_EVENT_PATH: ${{ github.event_path }}
FORCE_BREAKING_CHANGES_AGENT: ${{ inputs.force_breaking_changes_agent }}
run: |
SCRIPT_PATH="${{ github.action_path }}/scripts/should-spawn-breaking-changes.js"
RESULT=$(node "$SCRIPT_PATH")
SPAWN=$(echo "$RESULT" | jq -r '.spawn')
REASON=$(echo "$RESULT" | jq -r '.reason')
echo "SPAWN_BREAKING_CHANGES=$SPAWN" >> $GITHUB_ENV
echo "BREAKING_CHANGES_REASON=$REASON" >> $GITHUB_ENV
echo "Breaking changes agent: spawn=$SPAWN reason=\"$REASON\""
- name: Determine if license compliance agent should spawn
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_EVENT_PATH: ${{ github.event_path }}
FORCE_LICENSE_COMPLIANCE_AGENT: ${{ inputs.force_license_compliance_agent }}
run: |
SCRIPT_PATH="${{ github.action_path }}/scripts/should-spawn-license-compliance.js"
RESULT=$(node "$SCRIPT_PATH")
SPAWN=$(echo "$RESULT" | jq -r '.spawn')
REASON=$(echo "$RESULT" | jq -r '.reason')
echo "SPAWN_LICENSE_COMPLIANCE=$SPAWN" >> $GITHUB_ENV
echo "LICENSE_COMPLIANCE_REASON=$REASON" >> $GITHUB_ENV
echo "License compliance agent: spawn=$SPAWN reason=\"$REASON\""
- name: Determine if data classification agent should spawn
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_EVENT_PATH: ${{ github.event_path }}
FORCE_DATA_CLASSIFICATION_AGENT: ${{ inputs.force_data_classification_agent }}
run: |
SCRIPT_PATH="${{ github.action_path }}/scripts/should-spawn-data-classification.js"
RESULT=$(node "$SCRIPT_PATH")
SPAWN=$(echo "$RESULT" | jq -r '.spawn')
REASON=$(echo "$RESULT" | jq -r '.reason')
echo "SPAWN_DATA_CLASSIFICATION=$SPAWN" >> $GITHUB_ENV
echo "DATA_CLASSIFICATION_REASON=$REASON" >> $GITHUB_ENV
echo "Data classification agent: spawn=$SPAWN reason=\"$REASON\""
- name: Determine if deduplication agent should spawn
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_EVENT_PATH: ${{ github.event_path }}
FORCE_DEDUPLICATION_AGENT: ${{ inputs.force_deduplication_agent }}
run: |
SCRIPT_PATH="${{ github.action_path }}/scripts/should-spawn-deduplication.js"
RESULT=$(node "$SCRIPT_PATH")
SPAWN=$(echo "$RESULT" | jq -r '.spawn')
REASON=$(echo "$RESULT" | jq -r '.reason')
SIMILAR_PAIRS=$(echo "$RESULT" | jq -c '.similarPairs // []')
echo "SPAWN_DEDUPLICATION=$SPAWN" >> $GITHUB_ENV
echo "DEDUPLICATION_REASON=$REASON" >> $GITHUB_ENV
echo "DEDUP_SIMILAR_PAIRS=$SIMILAR_PAIRS" >> $GITHUB_ENV
echo "Deduplication agent: spawn=$SPAWN reason=\"$REASON\""
- name: Set up review prompt
shell: bash
run: |
# Create prompt header with context
PROMPT_HEADER="REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
"
if [[ -n "${{ inputs.custom_prompt }}" ]]; then
# Use custom prompt directly with header
PROMPT="${PROMPT_HEADER}${{ inputs.custom_prompt }}"
else
# Build dynamic prompt based on inputs
PROMPT="${PROMPT_HEADER}## CRITICAL CONSTRAINTS
Be extremely concise and sacrifice grammar for concision. Read-only mode: no shell commands, builds, or execution. Issues-only: report problems, never praise. If no issues: \"✅ No issues found\"
---
## REVIEW SCOPE
Focus on:
- Code quality/best practices for project technologies
- Bugs (especially critical paths, async ops)
- Performance (frontend/backend)
- Security (auth, APIs, data handling)
- Test coverage/quality
- Type safety, error handling, edge cases
- Maintainability/readability
**Diffs alone are not enough.** Read full file(s) to understand context. Code that looks wrong in isolation may be correct given surrounding logic.
### Incremental Review Guidelines (for PR updates)
**IMPORTANT: For PR synchronize events (subsequent pushes), be incremental:**
1. First, examine all existing review comments in this PR thread for context
2. **Extract existing issue IDs** from previous auto-review comments (look for **ID:** fields in comments starting with \\\"🤖 **Auto Review Issue:\\\")
3. For each previously reported issue:
- Check if the issue still exists in the current code state
- If it **STILL EXISTS**: Reuse the EXACT SAME ID from the previous review (even if the line number changed)
- If it's **RESOLVED**: Note it in your summary with the ID (don't create a new issue entry for it)
4. **CRITICAL: Only report previously mentioned issues if you can confirm they still exist** by examining the actual current code
5. For genuinely **NEW** issues: Generate a new ID using the ID Generation Rules
6. Clearly note when previously flagged issues have been resolved since the last review
7. When referencing issues originally identified by other tools (GitHub Copilot, Cursor, etc.), explicitly validate their current relevance and state \\\"Confirmed still present\\\" or \\\"Resolved since previous review\\\"
**ID Reuse Example:**
Previous review had: **ID:** login-sql-injection-f3a2 at line 42
Current review finds same issue at line 48 → Use SAME ID: **ID:** login-sql-injection-f3a2
(Update the line number to 48, but keep the ID unchanged)
**For initial PR reviews or if no previous comments exist, provide a full review.**
---
## AUTOMATED CHECKS
**Only report if violations found. Skip check if none detected.**
### PR Size Assessment (Check FIRST)
Flag if >15 files OR >800 lines changed:
🚨 **PR Too Large** **Files:** [N] **Lines:** [N] **Severity:** HIGH **Category:** maintainability
This PR is doing too much. Suggest 2-4 focused PRs split by: (1) logical concern (refactoring vs features vs infra vs deps) and (2) file/directory groupings. Format: \"PR 1: [description] - [files]\"
### External Domain URLs
Flag URLs to domains other than reown.com, walletconnect.com, walletconnect.org:
🔒 **External Domain URL** (Non-blocking) **URL:** [url] **File:** [path:line] - Verify intentional, review security implications.
### Static Resource Cache-Control
Flag static files (.woff, .woff2, .ttf, .jpg, .png, .css, .js, .mp4, etc.) with max-age < 31536000 or missing explicit Cache-Control:
⚠️ **Cache-Control Issue** **Resource:** [url] **File:** [path:line] **Current:** [value] **Recommendation:** \"Cache-Control: public, max-age=31536000, immutable\"
### GitHub Actions Workflow Security
Scan .github/workflows/*.y*ml for:
- **CRITICAL:** pull_request_target + PR head checkout (github.event.pull_request.head.*) = arbitrary code execution
- **HIGH:** pull_request_target + script execution
- **MEDIUM:** Any pull_request_target usage (runs with secrets)
Format: 🚨 **GitHub Actions Security Risk** **Severity:** [level] **File:** [path:line] **Pattern:** [issue] **Recommendation:** [fix]
### WalletConnect Pay Architecture
Flag anti-patterns in payment/wallet/transaction code:
1. **CRITICAL:** Cross-service DB access (imports, queries, connections) → 🚨 Services must use APIs
2. **HIGH:** Missing idempotency keys in POST/PUT/PATCH/DELETE → ⚠️ Extract key, check store, return cached response
3. **HIGH:** External calls without timeout/retry → ⚠️ Add timeout, retry+backoff, circuit breaker
4. **HIGH:** Event consumers (SQS/SNS/Kafka) without message deduplication → ⚠️ Check message ID before mutations
5. **MEDIUM:** Multi-step workflows without saga compensation → ⚠️ Add rollback/compensating events
6. **MEDIUM:** State transitions without trace context → ⚠️ Add structured logging with traceId/correlationId"
if [[ "$SPAWN_LICENSE_COMPLIANCE" == "true" ]]; then
PROMPT="$PROMPT
---
## LICENSE COMPLIANCE SUBAGENT
Based on PR analysis: ${LICENSE_COMPLIANCE_REASON}
Spawn ONE specialized subagent to check dependency licenses.
### Instructions:
Use the Task tool with subagent_type=\"general-purpose\" to launch the agent. In the prompt include:
1. \"Read your spec file at ${{ github.action_path }}/agents/review-license-compliance.md and follow its instructions.\"
2. PR number: ${{ github.event.pull_request.number }}, Repository: ${{ github.repository }}
3. The list of changed files in this PR
After the agent completes, merge its findings into your consolidated output.
- Use the agent's lic- prefixed IDs as-is
- Deduplicate if you found the same issue independently (prefer lic- prefixed ID)
- Sort all findings by severity: CRITICAL > HIGH > MEDIUM > LOW"
fi
# Conditionally add breaking changes subagent instructions
if [[ "$SPAWN_BREAKING_CHANGES" == "true" ]]; then
PROMPT="$PROMPT
---
## BREAKING CHANGES SUBAGENT
Based on PR analysis: ${BREAKING_CHANGES_REASON}
Spawn ONE specialized subagent to detect breaking changes.
### Instructions:
Use the Task tool with subagent_type=\"general-purpose\" to launch the agent. In the prompt include:
1. \"Read your spec file at ${{ github.action_path }}/agents/review-breaking-changes.md and follow its instructions.\"
2. PR number: ${{ github.event.pull_request.number }}, Repository: ${{ github.repository }}
3. The list of changed files in this PR
After the agent completes, merge its findings into your consolidated output.
- Use the agent's brk- prefixed IDs as-is
- Deduplicate if you found the same issue independently (prefer brk- prefixed ID)
- Sort all findings by severity: CRITICAL > HIGH > MEDIUM > LOW"
fi
# Conditionally add data classification subagent instructions
if [[ "$SPAWN_DATA_CLASSIFICATION" == "true" ]]; then
PROMPT="$PROMPT
---
## DATA CLASSIFICATION SUBAGENT
Based on PR analysis: ${DATA_CLASSIFICATION_REASON}
Spawn ONE specialized subagent to check data classification policy compliance.
### Instructions:
Use the Task tool with subagent_type=\"general-purpose\" to launch the agent. In the prompt include:
1. \"Read your spec file at ${{ github.action_path }}/agents/review-data-classification.md and follow its instructions.\"
2. PR number: ${{ github.event.pull_request.number }}, Repository: ${{ github.repository }}
3. The list of changed files in this PR
After the agent completes, merge its findings into your consolidated output.
- Use the agent's dcl- prefixed IDs as-is
- Deduplicate if you found the same issue independently (prefer dcl- prefixed ID)
- Sort all findings by severity: CRITICAL > HIGH > MEDIUM > LOW"
fi
# Conditionally add deduplication subagent instructions
if [[ "$SPAWN_DEDUPLICATION" == "true" ]]; then
PROMPT="$PROMPT
---
## DEDUPLICATION SUBAGENT
Based on PR analysis: ${DEDUPLICATION_REASON}
Similar file pairs detected:
${DEDUP_SIMILAR_PAIRS}
Spawn ONE specialized subagent to analyze code duplication.
### Instructions:
Use the Task tool with subagent_type=\"general-purpose\" to launch the agent. In the prompt include:
1. \"Read your spec file at ${{ github.action_path }}/agents/review-deduplication.md and follow its instructions.\"
2. PR number: ${{ github.event.pull_request.number }}, Repository: ${{ github.repository }}
3. The list of changed files in this PR
4. The similar file pairs data: ${DEDUP_SIMILAR_PAIRS}
After the agent completes, merge its findings into your consolidated output.
- Use the agent's dup- prefixed IDs as-is
- Deduplicate if you found the same issue independently (prefer dup- prefixed ID)
- Sort all findings by severity: CRITICAL > HIGH > MEDIUM > LOW"
fi
# Add project context
if [[ -n "${{ inputs.project_context }}" ]]; then
PROMPT="$PROMPT
**Project-specific context:**
${{ inputs.project_context }}"
fi
# Add response format guidelines
PROMPT="$PROMPT
---
## RESPONSE FORMAT
For incremental reviews: Start with \"🔄 Incremental Review:\" and focus only on changes since last review. If no new issues: \"✅ No new issues found in latest commits\"
For full reviews: Be concise - ONLY report issues that need fixing. If no issues: \"✅ No issues found\"
Wrap ALL issues in collapsed <details> section. No praise, issues-only.
**Issue Format:**
<details>
<summary>Found N issue(s)</summary>
#### Issue 1: Brief description
**ID:** {file-slug}-{semantic-slug}-{hash}
**File:** path/to/file.ext:123
**Severity:** CRITICAL/HIGH/MEDIUM/LOW
**Category:** security/performance/code_quality/breaking_change
**Context:**
- **Pattern:** What the problematic code pattern is
- **Risk:** Why it's a problem technically
- **Impact:** Potential consequences (exploit, data loss, etc.)
- **Trigger:** Under what conditions this becomes exploitable
**Recommendation:** Fix with minimal code snippet (1-10 lines).
</details>
**ID Generation:** {filename}-{2-4-key-terms}-{SHA256(path+desc).substr(0,4)}
Example: login-sql-injection-f3a2
**Recommendation Guidelines:** Include focused code snippets showing exact fix. DO: show specific changes needed. DON'T: provide full implementations or boilerplate.
**Example:**
<details>
<summary>Found 1 issue(s)</summary>
#### Issue 1: SQL injection in user query
**ID:** users-sql-injection-f3a2
**File:** src/database/users.ts:45
**Severity:** HIGH
**Category:** security
**Context:**
- **Pattern:** Query at line 45 builds SQL via string concatenation with user-provided \`userId\`
- **Risk:** Allows arbitrary SQL injection via crafted input (e.g., \`1' OR '1'='1\`)
- **Impact:** Unauthorized data access, modification, or database destruction
- **Trigger:** Any endpoint accepting user input that reaches this query
**Recommendation:** Use parameterized queries:
\\\`\\\`\\\`typescript
const result = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
\\\`\\\`\\\`
</details>
**Rules:** Use \\\"Issue N:\\\" not \\\"#N\\\". Include line numbers. Include code snippets in recommendations
**Feedback Style:** Provide constructive feedback with specific suggestions. Consider impact on system architecture and user experience. Focus exclusively on problems and their solutions"
fi
# Set environment variable for the next step
echo "REVIEW_PROMPT<<EOF" >> $GITHUB_ENV
echo "$PROMPT" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Check timeout_minutes deprecation
shell: bash
run: |
if [[ -n "${{ inputs.timeout_minutes }}" ]]; then
echo "::warning::The 'timeout_minutes' input is deprecated and has no effect in claude-code-action@v1. Please use job-level 'timeout-minutes' instead. See: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes"
fi
- name: Automatic PR Review
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ inputs.anthropic_api_key }}
prompt: ${{ env.REVIEW_PROMPT }}
track_progress: true
claude_args: --model ${{ inputs.model }} --allowedTools "Read,Glob,Grep,Task,WebFetch"
allowed_bots: devin-ai-integration[bot]
- name: Extract findings from Claude's comment
if: inputs.comment_pr_findings == 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
run: |
echo "Extracting findings from Claude's PR comment..."
SCRIPT_PATH="${{ github.action_path }}/scripts/extract-findings-from-comment.js"
if [[ ! -f "$SCRIPT_PATH" ]]; then
echo "::warning::Extract findings script not found at $SCRIPT_PATH"
echo "[]" > findings.json
exit 0
fi
chmod +x "$SCRIPT_PATH"
node "$SCRIPT_PATH"
- name: Ensure GitHub CLI and jq for inline comments
if: inputs.comment_pr_findings == 'true'
shell: bash
run: |
# Install GitHub CLI if needed
if ! command -v gh >/dev/null 2>&1; then
echo "::group::Installing GitHub CLI"
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update && sudo apt-get install -y gh
elif command -v brew >/dev/null 2>&1; then
brew install gh
else
echo "::warning::Unable to auto-install GitHub CLI on this runner. Please ensure gh is available."
fi
echo "::endgroup::"
else
echo "GitHub CLI already available"
fi
# Install jq if needed
if ! command -v jq >/dev/null 2>&1; then
echo "::group::Installing jq"
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update && sudo apt-get install -y jq
elif command -v brew >/dev/null 2>&1; then
brew install jq
else
echo "::warning::Unable to auto-install jq on this runner. Please ensure jq is available."
fi
echo "::endgroup::"
else
echo "jq already available"
fi
- name: Post inline findings comments
if: inputs.comment_pr_findings == 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
SILENCE_AUTO_REVIEW_COMMENTS: ${{ env.SILENCE_AUTO_REVIEW_COMMENTS }}
run: |
if [[ ! -f findings.json ]]; then
echo "findings.json not present, skipping inline comment step."
exit 0
fi
# Check if findings.json has any findings
FINDINGS_COUNT=$(jq 'length' findings.json 2>/dev/null || echo "0")
if [[ "$FINDINGS_COUNT" -eq 0 ]]; then
echo "No findings to comment on (findings.json is empty)."
exit 0
fi
echo "Found $FINDINGS_COUNT findings to comment on."
SCRIPT_PATH="${{ github.action_path }}/scripts/comment-pr-findings.js"
if [[ ! -f "$SCRIPT_PATH" ]]; then
echo "::warning::Inline comment script not found at $SCRIPT_PATH"
exit 0
fi
chmod +x "$SCRIPT_PATH"
node "$SCRIPT_PATH"