Feat 310 translate GitHub issue bot to python#347
Feat 310 translate GitHub issue bot to python#347zeus2611 wants to merge 4 commits intoappwrite:mainfrom
Conversation
WalkthroughThis pull request introduces a new Python-based GitHub Issue Bot feature. The addition includes a webhook handler ( Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@python/github-issue-bot/src/github.py`:
- Around line 39-44: The current logic that re-serializes a parsed payload_body
dict (the if isinstance(payload_body, dict) branch) breaks GitHub webhook HMAC
verification because the raw HTTP body bytes must be used; change the code to
obtain and use the raw request bytes (prefer a runtime-provided
raw_body/rawBody/bodyBinary if available) before any JSON parsing, remove or
replace the dict re-serialization branch with an explicit failure/error path if
only a parsed dict is available, and update any logging that uses print() (e.g.,
the call referenced around line 88) to use context.error() for consistent
logging; target the payload_body handling in github.py and the related signature
verification call sites when making these changes.
In `@python/github-issue-bot/src/utils.py`:
- Line 19: The environment-variable presence check in the conditional that
currently reads "if key not in obj or obj[key] is None or obj[key] == 0:" is
incorrect because environment values are strings and empty strings should be
treated as falsy; update that conditional in utils.py to test for
falsy/empty-string values (for example use "if key not in obj or not obj[key]"
or explicitly check "obj[key] == ''") so blank environment variables are
rejected; ensure you modify the exact conditional expression where obj[key] is
tested to cover empty string and other falsy cases.
In `@README.md`:
- Line 24: Update the README table row for "Github Issue Bot" to correct the
title to "GitHub Issue Bot" and replace the Python column's placeholder emoji
(🏗️) with a link to the new Python template directory (e.g.,
python/github-issue-bot), mirroring the link format used for other languages;
edit the table cell in the same row as "node/github-issue-bot" so it reads
[✅](python/github-issue-bot) and ensure "Github" is capitalized as "GitHub" in
that row.
🧹 Nitpick comments (4)
python/github-issue-bot/requirements.txt (1)
1-1: Consider pinning the PyGithub version.An unpinned dependency can lead to non-reproducible builds and unexpected breakage if a new major version introduces breaking changes. Consider pinning to the version you tested with (e.g.,
PyGithub==2.x.y).python/github-issue-bot/README.md (1)
15-15: Sample signature value doesn't match the expected format.The
x-hub-signature-256header from GitHub follows the formatsha256=<hex-digest>. The sample valueh74ba0jbla01lagudfois misleading. Consider using a realistic placeholder likesha256=abc123....python/github-issue-bot/src/main.py (1)
23-26: Duplicate body parsing.The body is already parsed inside
is_issue_opened_event(github.py Line 64-67). Consider having a single parsing step earlier and passing the parsed payload to both methods, or havingis_issue_opened_eventaccept the payload directly.python/github-issue-bot/src/github.py (1)
75-93:post_commentsilently swallows missing data — usecontext.log/context.errorfor consistency.Line 88 uses
print()while the rest of the codebase (main.py) usescontext.log()/context.error(). Also, silently returning on missing data makes debugging harder — the caller in main.py won't know the comment wasn't posted.Consider either raising an exception (which main.py already catches) or accepting
contextto log properly.
| if isinstance(payload_body, dict): | ||
| payload_bytes = json.dumps(payload_body, separators=(',', ':')).encode('utf-8') | ||
| elif isinstance(payload_body, str): | ||
| payload_bytes = payload_body.encode('utf-8') | ||
| else: | ||
| payload_bytes = payload_body |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "*.js" -o -name "*.ts" | grep -i "github-issue-bot" | head -20Repository: appwrite/templates
Length of output: 393
🏁 Script executed:
git ls-files | grep -E "(node|javascript|typescript)" | grep -i "github-issue-bot"Repository: appwrite/templates
Length of output: 837
🏁 Script executed:
find . -type f \( -name "*.py" -o -name "*.js" -o -name "*.ts" \) | grep -i "github-issue-bot" | head -30Repository: appwrite/templates
Length of output: 510
🏁 Script executed:
cat -n python/github-issue-bot/src/github.pyRepository: appwrite/templates
Length of output: 3647
🏁 Script executed:
cat -n python/github-issue-bot/src/main.pyRepository: appwrite/templates
Length of output: 1613
🏁 Script executed:
cat -n node/github-issue-bot/src/github.jsRepository: appwrite/templates
Length of output: 1400
🏁 Script executed:
cat -n node/github-issue-bot/src/main.jsRepository: appwrite/templates
Length of output: 1010
🏁 Script executed:
cat -n node-typescript/github-issue-bot/src/github.tsRepository: appwrite/templates
Length of output: 1540
🏁 Script executed:
find python/github-issue-bot -type f \( -name "*test*" -o -name "*spec*" \) | head -20Repository: appwrite/templates
Length of output: 44
🏁 Script executed:
ls -la python/github-issue-bot/Repository: appwrite/templates
Length of output: 417
🏁 Script executed:
find . -path "*/python/github-issue-bot*" -type fRepository: appwrite/templates
Length of output: 294
Re-serializing a parsed dict will break webhook signature verification.
GitHub signs the raw HTTP request body. The Node.js reference implementation (using @octokit/webhooks-methods) correctly verifies against req.bodyBinary, while the Python code attempts to handle a parsed dict via json.dumps(separators=(',', ':')). This will not reproduce the original bytes (whitespace, key order, Unicode escapes, etc.), causing HMAC verification to always fail if the Appwrite Python runtime ever delivers context.req.body as a parsed dict.
You should capture the raw body bytes before any JSON parsing. If the Appwrite Python runtime provides a rawBody or bodyBinary equivalent, use that. If the body is always a string in practice, at minimum document that assumption and remove the dict branch (which gives a false sense of safety).
Additionally, line 88 uses print() instead of context.error() for consistency with the logging pattern in main.py.
Proposed fix — prefer raw body, fail explicitly for dicts
payload_body = context.req.body
if not payload_body:
return False
-
- if isinstance(payload_body, dict):
- payload_bytes = json.dumps(payload_body, separators=(',', ':')).encode('utf-8')
- elif isinstance(payload_body, str):
+
+ if isinstance(payload_body, dict):
+ # Cannot reliably verify signature against a re-serialized dict.
+ # Use context.req.bodyRaw or equivalent if available.
+ raise ValueError("Cannot verify webhook signature: raw body is required, but received parsed dict")
+ elif isinstance(payload_body, str):
payload_bytes = payload_body.encode('utf-8')
else:
payload_bytes = payload_body🤖 Prompt for AI Agents
In `@python/github-issue-bot/src/github.py` around lines 39 - 44, The current
logic that re-serializes a parsed payload_body dict (the if
isinstance(payload_body, dict) branch) breaks GitHub webhook HMAC verification
because the raw HTTP body bytes must be used; change the code to obtain and use
the raw request bytes (prefer a runtime-provided raw_body/rawBody/bodyBinary if
available) before any JSON parsing, remove or replace the dict re-serialization
branch with an explicit failure/error path if only a parsed dict is available,
and update any logging that uses print() (e.g., the call referenced around line
88) to use context.error() for consistent logging; target the payload_body
handling in github.py and the related signature verification call sites when
making these changes.
What does this PR do?
Adds a new Python template for a GitHub Issue Bot that automatically responds to newly opened issues on a GitHub repository. This is a Python port of the existing Node.js github-issue-bot template.
Test Plan
The function was manually deployed to an Appwrite instance and tested end-to-end:
Related PRs and Issues
#310
Have you read the Contributing Guidelines on issues?
Yes, I have read and followed the contributing guidelines.
Summary by CodeRabbit
New Features
Documentation
Chores