fix: support both classic and fine-grained GitHub tokens

- Update token validation to support github_pat_ tokens in addition to ghp_ tokens
- Add trust proxy configuration for reverse proxy deployments
- Update port configuration from 3002 to 3003 in docker-compose
- Add request body validation in webhook controller
- Ensure consistent token pattern handling across services

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jonathan
2025-05-30 12:57:34 -05:00
parent 92a3543db4
commit a692ff096c
6 changed files with 28 additions and 5 deletions

View File

@@ -2,6 +2,11 @@
NODE_ENV=development
PORT=3002
# Trust Proxy Configuration
# Set to 'true' when running behind reverse proxies (nginx, cloudflare, etc.)
# This allows proper handling of X-Forwarded-For headers for rate limiting
TRUST_PROXY=false
# ============================
# SECRETS CONFIGURATION
# ============================

View File

@@ -2,7 +2,7 @@ services:
webhook:
build: .
ports:
- "8082:3002"
- "8082:3003"
volumes:
- .:/app
- /app/node_modules
@@ -11,7 +11,8 @@ services:
- ${HOME}/.claude:/home/claudeuser/.claude
environment:
- NODE_ENV=production
- PORT=3002
- PORT=3003
- TRUST_PROXY=${TRUST_PROXY:-true}
- AUTHORIZED_USERS=${AUTHORIZED_USERS:-Cheffromspace}
- BOT_USERNAME=${BOT_USERNAME:-@MCPClaude}
- DEFAULT_GITHUB_OWNER=${DEFAULT_GITHUB_OWNER:-Cheffromspace}
@@ -31,7 +32,7 @@ services:
- GITHUB_WEBHOOK_SECRET=${GITHUB_WEBHOOK_SECRET}
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3002/health"]
test: ["CMD", "curl", "-f", "http://localhost:3003/health"]
interval: 30s
timeout: 10s
retries: 3

View File

@@ -114,6 +114,12 @@ export const handleWebhook: WebhookHandler = async (req, res) => {
const event = req.headers['x-github-event'] as string;
const delivery = req.headers['x-github-delivery'] as string;
// Check if request body exists
if (!req.body) {
logger.error('Webhook request missing body');
return res.status(400).json({ error: 'Missing request body' });
}
// Log webhook receipt with key details (sanitize user input to prevent log injection)
logger.info(
{

View File

@@ -15,6 +15,14 @@ import type {
import { execSync } from 'child_process';
const app = express();
// Configure trust proxy setting based on environment
// Set TRUST_PROXY=true when running behind reverse proxies (nginx, cloudflare, etc.)
const trustProxy = process.env['TRUST_PROXY'] === 'true';
if (trustProxy) {
app.set('trust proxy', true);
}
const PORT = parseInt(process.env['PORT'] ?? '3003', 10);
const appLogger = createLogger('app');
const startupMetrics = new StartupMetrics();

View File

@@ -55,7 +55,9 @@ export async function processCommand({
const githubToken = secureCredentials.get('GITHUB_TOKEN');
// In test mode, skip execution and return a mock response
if (process.env['NODE_ENV'] === 'test' || !githubToken?.includes('ghp_')) {
// Support both classic (ghp_) and fine-grained (github_pat_) GitHub tokens
const isValidGitHubToken = githubToken && (githubToken.includes('ghp_') || githubToken.includes('github_pat_'));
if (process.env['NODE_ENV'] === 'test' || !isValidGitHubToken) {
logger.info(
{
repo: repoFullName,

View File

@@ -24,7 +24,8 @@ let octokit: Octokit | null = null;
function getOctokit(): Octokit | null {
if (!octokit) {
const githubToken = secureCredentials.get('GITHUB_TOKEN');
if (githubToken?.includes('ghp_')) {
// Support both classic (ghp_) and fine-grained (github_pat_) GitHub tokens
if (githubToken && (githubToken.includes('ghp_') || githubToken.includes('github_pat_'))) {
octokit = new Octokit({
auth: githubToken,
userAgent: 'Claude-GitHub-Webhook'