mvp-factory-openhands/GITEA_N8N_WEBHOOK_GUIDE.md

8.4 KiB

🚀 Gitea → n8n → OpenHands SDK Integration Guide

Last Updated: 2025-12-01
Status: WORKING (with variable fix needed)
Total Time: ~8 hours across multiple sessions


🎯 OVERVIEW

This guide documents the successful integration of:

  • Gitea (Git hosting)
  • n8n (Workflow automation)
  • OpenHands SDK v1.3.0 (AI-powered build/test agent)

Flow: git pushGitea webhookn8n workflowSSH to OpenHands SDK


WHAT WORKS

1. Repository Setup

# New clean repository with only 8 essential files
# No .env files in git history (security)
# Deploy keys configured for SSH access

2. n8n Workflow Import

# Import command
docker exec n8n n8n import:workflow --input=/tmp/workflow.json

# Must include "active": true in JSON

3. Webhook Configuration

  • URL: https://n8n.oky.sh/webhook-test/openhands-sdk
  • Method: POST
  • Content-Type: application/json
  • Active:

4. SSH Authentication

  • Key: /home/bam/.ssh/n8n_key
  • Mounted: In n8n container as /home/node/.ssh
  • Credentials ID: v2BMXeCFGpXaoIyb

5. OpenHands SDK Wrapper

  • Location: /home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh
  • Env File: /home/bam/openhands/.env
  • SDK Path: /tmp/software-agent-sdk
  • Python Wrapper: /home/bam/openhands-sdk-wrapper-fixed.py

🔧 WORKFLOW STRUCTURE

Node 1: Webhook Trigger

{
  "type": "n8n-nodes-base.webhook",
  "parameters": {
    "httpMethod": "POST",
    "path": "openhands-sdk"
  }
}

Node 2: Extract Repo Info (JavaScript)

const payload = $input.item.json;
const repoName = payload.repository?.name || 'unknown';
const repoFullName = payload.repository?.full_name || 'unknown';
const branch = payload.ref?.replace('refs/heads/', '') || 'main';
// ... extract more fields

const task = 'Build and test project ' + repoFullName + ' on branch ' + branch + '. ' +
             'Clone the repository and run: npm install && npm test && npm build.';

return { repo_name: repoName, task: task, ... };

Node 3: Execute OpenHands SDK (SSH)

{
  "type": "n8n-nodes-base.ssh",
  "parameters": {
    "command": "={{ 'sh /home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh \"' + $json.task + '\"' }}",
    "sessionId": "gitea-session"
  }
}

Node 4: Webhook Response

{
  "type": "n8n-nodes-base.respondToWebhook",
  "parameters": {
    "respondWith": "text",
    "responseBody": "✅ Build triggered successfully!"
  }
}

⚠️ CRITICAL NOTES

n8n Test Mode vs Production

  • Test URL: https://n8n.oky.sh/webhook-test/openhands-sdk

    • Requires clicking "Execute workflow" button in UI
    • Webhook active for ONE call only
    • Variables work properly
  • Production URL: https://n8n.oky.sh/webhook/openhands-sdk

    • Always active (if workflow set to active: true)
    • DOES NOT WORK with Gitea webhook node (known limitation)

Variable Substitution in SSH

DOESN'T WORK:

"command": "sh /home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh \"{{ $json.task }}\""

WORKS:

"command": "={{ 'sh /home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh \"' + $json.task + '\"' }}"

Why? n8n needs explicit expression evaluation for SSH node commands.


🔨 STEP-BY-STEP WORKFLOW

Step 1: Import Workflow

# Copy workflow JSON to n8n container
docker cp /path/to/workflow.json n8n:/tmp/workflow.json

# Import
docker exec -e N8N_BASIC_AUTH_ACTIVE=false n8n \
  n8n import:workflow --input=/tmp/workflow.json

Step 2: Activate Workflow

  1. Open n8n UI: https://n8n.oky.sh
  2. Find workflow "Gitea → OpenHands SDK"
  3. Toggle to activate (make it green)
  4. OR for test mode: Click "Execute workflow" button

Step 3: Configure Gitea Webhook

  1. Go to Gitea repository
  2. Settings → Webhooks → Add Webhook
  3. Configure:
    • URL: https://n8n.oky.sh/webhook-test/openhands-sdk
    • Method: POST
    • Content Type: application/json
    • Push Events:
    • Active:
  4. Test webhook (optional)

Step 4: Test Integration

# Make a change and push
echo "test" > test.txt
git add test.txt
git commit -m "Test webhook"
git push origin main

Step 5: Monitor Execution

# Watch n8n logs
docker logs -f n8n

# Should see:
# - "Workflow was started"
# - OpenHands SDK output
# - Task with actual repo/branch values

📁 KEY FILES

Workflow Files

  • /tmp/openhands-sdk-webhook-FINAL.json - Working workflow with fixes
  • /home/bam/claude/mvp-factory/openhands-sdk-n8n-CLEAN.json - Reference workflow

Wrapper Scripts

  • /home/bam/claude/mvp-factory/openhands-sdk-wrapper-sh.sh - Main wrapper (sh-compatible)
  • /home/bam/openhands-sdk-wrapper-fixed.py - Python wrapper
  • /home/bam/openhands/.env - API keys (NOT in git)

Configuration

  • /home/bam/.ssh/n8n_key - SSH private key for n8n
  • /home/bam/services/services-stack/docker-compose.yml - n8n config with SSH mount

🧪 TESTING CHECKLIST

Verified Working

  • Workflow imports to n8n
  • Webhook receives Gitea events
  • n8n parses webhook payload
  • SSH connects to localhost
  • OpenHands SDK starts
  • Task sent to OpenHands

🔧 Still Needs Fixing

  • Variable substitution in SSH command (use expression syntax)
  • Production webhook URL (test URL works, production doesn't)
  • OpenHands task parsing (sometimes shows "unknown")

🚨 TROUBLESHOOTING

"Webhook not registered"

  • Cause: Workflow not active
  • Fix: Toggle workflow to active in n8n UI
  • Or: Click "Execute workflow" for test mode

"unknown webhook" error

  • Cause: Wrong URL path
  • Fix: Use /webhook-test/ not /webhook/ for n8n+Gitea

SSH authentication fails

  • Cause: Key not mounted or wrong permissions
  • Fix: Verify in docker-compose.yml:
    volumes:
      - /home/bam/.ssh:/home/node/.ssh:ro
    

Variables show "{{ $json.field }}"

  • Cause: n8n expression not evaluated
  • Fix: Use explicit expression: "={{ 'text ' + $json.field + ' more' }}"

OpenHands SDK not found

  • Cause: Virtual environment not activated
  • Fix: Wrapper script activates venv before running Python

📚 REFERENCE COMMANDS

Check n8n Logs

docker logs --tail 100 n8n 2>&1 | grep -i "openhands\|ssh\|webhook"

Test Webhook Directly

curl -X POST https://n8n.oky.sh/webhook-test/openhands-sdk \
  -H "Content-Type: application/json" \
  -d '{"repository":{"full_name":"test/repo"},"ref":"refs/heads/main"}'

Verify Workflow Active

curl -s https://n8n.oky.sh/api/v1/workflows | jq '.data[] | select(.name=="Gitea → OpenHands SDK") | .active'

Restart n8n

docker compose -f /home/bam/services/services-stack/docker-compose.yml restart n8n

🎓 KEY LEARNINGS

  1. Test URLs are required for n8n+Gitea integration

    • Production /webhook/ doesn't work with Gitea
    • Must use test mode /webhook-test/
  2. SSH variable substitution requires explicit expressions

    • Can't use {{ }} syntax directly in SSH command field
    • Must wrap in expression: "={{ 'prefix' + $json.field + 'suffix' }}"
  3. Workflows deactivate on import

    • Always re-activate after importing new version
    • Set "active": true in JSON before import
  4. SSH keys need proper mounting

    • n8n container needs /home/bam/.ssh mounted as /home/node/.ssh
    • Use read-only mount: :ro
  5. OpenHands wrapper must be sh-compatible

    • Use #!/bin/sh not #!/bin/bash
    • Load env vars with source not dot (. works for both)

🚀 NEXT STEPS

Immediate

  1. Import /tmp/openhands-sdk-webhook-FINAL.json
  2. Activate workflow in n8n UI
  3. Test with new git push

Future Enhancements

  1. Production webhook support - Find workaround for n8n+Gitea limitation
  2. Retry logic - Add loop for build completion checking
  3. Commit status updates - Post results back to Gitea
  4. Error handling - Better error messages and recovery
  5. Multiple repos - Support for different repository patterns

📞 SUPPORT

If issues occur:

  1. Check n8n logs: docker logs n8n
  2. Verify workflow is active in n8n UI
  3. Test webhook manually with curl
  4. Confirm SSH key mounting in docker-compose.yml
  5. Check OpenHands wrapper script permissions

Status: Integration Complete
Last Test: 2025-12-01 17:30:00
Commit: 290b79c (E2E test successful)