GitHub webhook security automation that watches repositories, patches changed .js files with Gemini AI, and opens pull requests.
- Frontend: React + Vite
- Backend: Node.js 18+ + Express (ES modules)
- AI: Gemini via
@google/genai - GitHub API: GitHub REST via native
fetch - Persistence: Local JSON (
watchlist.json)
sekyu-ai/
├── backend/
│ ├── package.json
│ ├── server.js
│ ├── watchlist.json
│ ├── routes/
│ │ ├── watchlist.js
│ │ └── webhook.js
│ └── services/
│ ├── github.js
│ └── gemini.js
├── frontend/
│ ├── package.json
│ ├── src/
│ │ ├── main.jsx
│ │ ├── App.jsx
│ │ └── components/
│ │ ├── AddRepo.jsx
│ │ └── RepoList.jsx
│ └── vite.config.js
├── scripts/
│ └── test-webhook.js
├── .env.example
├── package.json
└── README.md
git clone https://github.com/<your-username>/SekyuAI.git
cd SekyuAI# Root dev tooling (concurrently)
npm install
# Backend and frontend dependencies
npm run install:allcp .env.example backend/.envOpen backend/.env and fill in every value:
GITHUB_PAT=your_github_personal_access_token_here
GEMINI_API_KEY=your_gemini_api_key_here
WEBHOOK_SECRET=your_webhook_secret_here
PORT=3000
| Variable | Description |
|---|---|
GITHUB_PAT |
GitHub Personal Access Token with repo scope |
GEMINI_API_KEY |
Google Gemini API key |
WEBHOOK_SECRET |
Random secret string used to validate HMAC-signed webhook payloads |
PORT |
Backend server port (default: 3000) |
Start both the backend and frontend with a single command from the project root:
npm run dev- Backend runs at http://localhost:3000
- Frontend runs at http://localhost:5173 (Vite default)
GitHub must be able to reach your local server to deliver webhook events. Use ngrok to create a public tunnel.
Follow the instructions at https://ngrok.com/download, or with Homebrew:
brew install ngrok/ngrok/ngrokIn a separate terminal (while npm run dev is running):
ngrok http 3000ngrok will display a Forwarding URL such as:
Forwarding https://a1b2c3d4.ngrok-free.app -> http://localhost:3000
Copy this URL — you will need it in the next step.
-
Go to your GitHub repository → Settings → Webhooks → Add webhook.
-
Set the fields as follows:
Field Value Payload URL <ngrok-url>/webhook(e.g.https://a1b2c3d4.ngrok-free.app/webhook)Content type application/jsonSecret The same value you used for WEBHOOK_SECRETinbackend/.envWhich events? Select Let me select individual events, then tick only Pushes -
Click Add webhook.
GitHub will immediately send a ping event; the backend will respond with 200 OK.
Security note: Every incoming webhook payload is validated against the
X-Hub-Signature-256header using HMAC SHA-256 with yourWEBHOOK_SECRET. Requests with an invalid or missing signature are rejected with401 Unauthorized.
Use these curl commands to verify the watchlist API while the backend is running.
curl -s http://localhost:3000/api/watchlist | jqcurl -s -X POST http://localhost:3000/api/watchlist \
-H "Content-Type: application/json" \
-d '{"repo": "owner/repository-name"}' | jqcurl -s -X DELETE "http://localhost:3000/api/watchlist/owner%2Frepository-name" | jqYou can simulate a GitHub push event without touching GitHub:
node scripts/test-webhook.jsThe script reads WEBHOOK_SECRET from backend/.env (or from the environment), builds a mock push payload, signs it with HMAC SHA-256, and POSTs it to http://localhost:3000/webhook.
Follow these steps for a full end-to-end demonstration:
curl -s -X POST http://localhost:3000/api/watchlist \
-H "Content-Type: application/json" \
-d '{"repo": "your-username/your-repo"}' | jqConfirm it appears in the list:
curl -s http://localhost:3000/api/watchlist | jqIn the watched repository, make a change to any .js file and push it:
echo "// demo change" >> src/index.js
git add src/index.js
git commit -m "demo: trigger SekyuAI"
git push origin mainGitHub delivers a push event to your ngrok URL → backend validates the HMAC signature → Gemini reviews and patches the changed .js files.
Open the watched repository on GitHub. SekyuAI will have opened a new pull request containing the AI-generated security patches. Review the diff and merge if appropriate.