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
|
name: Droid Code Review
on:
issue_comment:
types: [created]
concurrency:
group: droid-review-${{ github.event.issue.number }}
cancel-in-progress: true
permissions:
pull-requests: write
contents: read
issues: write
jobs:
code-review:
runs-on: ubuntu-latest
timeout-minutes: 20
# Only run on PR comments that contain "@droid review" from authorized users
if: |
github.event.issue.pull_request &&
contains(github.event.comment.body, '@droid review') &&
(
github.event.comment.user.login == 'vstakhov' ||
github.event.comment.user.login == 'moisseev' ||
github.event.comment.user.login == 'fatalbanana'
)
steps:
- name: Acknowledge review start with reaction
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
/repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
-f content='eyes'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkout PR branch
run: |
gh pr checkout ${{ github.event.issue.number }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install Droid CLI
run: |
curl -fsSL https://app.factory.ai/cli | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH
"$HOME/.local/bin/droid" --version
- name: Configure git identity
run: |
git config user.name "Droid Code Reviewer"
git config user.email "droid@factory.ai"
- name: Perform automated code review
env:
FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
cat > prompt.txt << 'EOF'
You are an automated code review system for the Rspamd mail filtering project.
Review the PR diff and identify clear issues that need to be fixed.
First, use the Web Fetch tool to get the full PR context from:
https://github.com/${{ github.repository }}/pull/${{ github.event.issue.number }}
This will provide you with:
- PR title, description, and metadata
- Complete diff with line numbers for positioning comments
- Changed files with their status
- Existing comments and review threads (to avoid duplicates)
Task: After fetching the PR data, review the code changes and directly submit your findings using the GitHub CLI.
## Rspamd-Specific C/C++ Review Guidelines
### Memory Management (CRITICAL)
- All C allocations MUST use rspamd_mempool or g_malloc/g_free
- Never use raw malloc/free without proper cleanup
- Check for memory leaks: every allocation must have a matching free
- Verify mempool ownership: objects allocated from mempool are freed when pool is destroyed
- Use rspamd_mempool_new() / rspamd_mempool_delete() properly
- Check for use-after-free: accessing freed memory or destroyed mempool objects
### C++ Standards and Containers
- Code MUST use C++20 standard features where appropriate
- DO NOT use std::unordered_map or std::hash - use ankerl::unordered_dense instead
- Prefer std::string_view over const std::string& for read-only strings
- Use auto with structured bindings where it improves readability
- Check for proper RAII: resources acquired in constructors, released in destructors
### Logging
- Debug logging uses custom printf format (see src/libutil/printf.h)
- Lua rspamd_logger uses %s for all argument placeholders
- Never use format strings from untrusted input (format string vulnerabilities)
- Check for proper log levels: debug/info/warning/error
### Lua Integration
- Lua stack management: every lua_push* must be balanced with proper stack cleanup
- Use LUA_TRACE_POINT at function entry for debugging
- Check lua_check_* return values before dereferencing
- Verify proper class registration with rspamd_lua_setclass
- Never hold Lua references across yield points without proper handling
### Security Issues
- Buffer overflows: check array bounds, string lengths
- Integer overflows in size calculations
- SQL/command injection in external calls
- Path traversal in file operations
- Unvalidated redirects
- DoS vulnerabilities: unbounded loops, excessive memory allocation
- NULL pointer dereferences
### Concurrency and Threading
- Race conditions on shared data
- Missing locks or improper lock ordering (deadlocks)
- Use of thread-unsafe functions
- Proper event loop integration (libev)
### Error Handling
- Check return values from all functions that can fail
- Proper error propagation to callers
- Resource cleanup in error paths
- Avoid silent failures
### Code Quality
- Dead/unreachable code
- Incorrect operator usage (bitwise vs logical, assignment in conditions)
- Off-by-one errors in loops
- Missing break in switch statements
- Unintended fallthrough
- Use-before-initialization
- Signed/unsigned comparison issues
Comment format:
- Clearly describe the issue: "Memory leak: allocated buffer not freed on error path"
- Provide a concrete fix: "Add g_free(buffer) before returning NULL"
- When possible, suggest exact code change
- Be specific about why it's a problem: "This will leak memory if parsing fails"
- Use technical language, no emojis
Skip commenting on:
- Code style and formatting (clang-format handles this)
- Naming conventions
- Minor performance optimizations
- Architectural decisions
- Test coverage (unless tests are broken)
- Documentation (unless it's misleading)
Use the fetched PR data to:
- Avoid repeating resolved issues unless the problem still exists
- Reference ongoing discussions when adding follow-ups
- Prefer replying to existing threads instead of creating duplicates
- Ignore your own previous resolved comments
- **CRITICAL: Stop repeating dismissed feedback** - If a maintainer (vstakhov, moisseev, fatalbanana) has replied to your comment explaining why something is intentional, by design, or not a bug, DO NOT report the same issue again in subsequent reviews
- **Respect maintainer decisions** - When a human reviewer disagrees with your assessment and provides rationale, defer to their judgment and do not re-raise the same concern
- **Check comment thread context** - Before posting a comment, review all replies in existing threads. If a maintainer has already addressed your concern with an explanation, skip that issue entirely
- **Recognize intentional design** - Code that a maintainer explicitly defends as "intentional behavior" or "by design" should not be flagged as a bug, even if it doesn't match your expectations
Position calculation:
- Use the line position from the diff data (line number in diff, not file)
- Comments must align with exact changed lines only
How to submit your review:
Use the GitHub CLI (gh) to submit your review. The PR number is ${{ github.event.issue.number }}
and repository is ${{ github.repository }}.
GitHub CLI command examples:
- For inline comments with review summary: gh pr review ${{ github.event.issue.number }} --comment --body "Review summary text here"
- To request changes with inline comments: gh pr review ${{ github.event.issue.number }} --request-changes --body "Found issues that need fixing"
- To approve: gh pr review ${{ github.event.issue.number }} --approve --body "No issues found"
- For inline comments on specific lines: gh pr review ${{ github.event.issue.number }} --comment --body-file review.txt (where review.txt contains formatted review)
CRITICAL: DO NOT post test comments or experiment with the API - every comment is visible to maintainers and contributors.
You must use the correct command on the first attempt. If unsure about syntax, default to: gh pr review ${{ github.event.issue.number }} --comment --body "your message"
Guidelines:
- Submit at most 10 comments total, prioritizing the most critical issues
- Each comment must be actionable and clear about what needs to be fixed
- Check for existing bot comments before posting duplicates
- Include a summary in the review body when submitting multiple inline comments
- If no issues found, post a single approval comment
EOF
# Run droid exec with the prompt
echo "Running code review analysis and submitting results..."
droid exec --auto high --model claude-sonnet-4-5-20250929 -f prompt.txt
- name: Post review completion comment
if: ${{ success() }}
run: |
gh pr comment ${{ github.event.issue.number }} --body "Code review completed successfully. The review has been submitted."
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Dismiss previous change requests if approved
if: ${{ success() }}
run: |
# Get all reviews for this PR
REVIEWS=$(gh api "/repos/${{ github.repository }}/pulls/${{ github.event.issue.number }}/reviews" --jq '.[] | select(.state == "CHANGES_REQUESTED" and .user.login == "github-actions[bot]") | .id')
# Dismiss each change request review
for REVIEW_ID in $REVIEWS; do
echo "Dismissing review $REVIEW_ID"
gh api \
--method PUT \
-H "Accept: application/vnd.github+json" \
"/repos/${{ github.repository }}/pulls/${{ github.event.issue.number }}/reviews/$REVIEW_ID/dismissals" \
-f message="Dismissed after new approval" || echo "Failed to dismiss review $REVIEW_ID (may already be dismissed)"
done
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload debug artifacts on failure
if: ${{ failure() }}
uses: actions/upload-artifact@v4
with:
name: droid-review-debug-${{ github.run_id }}
path: |
prompt.txt
${{ runner.home }}/.factory/logs/droid-log-single.log
${{ runner.home }}/.factory/logs/console.log
if-no-files-found: ignore
retention-days: 7
|