diff --git a/Architecture-Overview.md b/Architecture-Overview.md new file mode 100644 index 0000000..af5fc80 --- /dev/null +++ b/Architecture-Overview.md @@ -0,0 +1,154 @@ +# Architecture Overview + +## System Diagram + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Developer Workflow │ +│ git push → Gitea (git.falahos.my) → Actions Runner │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Gitea Actions (Docker Swarm) │ +│ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ CI │ │ Deploy │ │ Sync │ │ Health │ │ +│ │ lint + │ │ git push │ │ cPanel + │ │ every │ │ +│ │ security │ │ + WP API │ │ Nextcloud│ │ 30min │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +└─────────────────────────────────────────────────────────────┘ + │ + ┌─────────────┴──────────────┐ + ▼ ▼ +┌──────────────────────┐ ┌──────────────────────────┐ +│ cPanel (Hosting) │ │ Contabo (Docker Host) │ +│ │ │ │ +│ WordPress Site │ │ Gitea (git.falahos.my) │ +│ ummah.falahos.my │ │ Nextcloud │ +│ │ │ team.falahos.my │ +│ Hermes Plugin: │ │ │ +│ ┌───────────────┐ │ │ Gitea Actions Runner │ +│ │ REST API │ │ │ (Docker Swarm service) │ +│ │ hermes/v1/* │ │ │ │ +│ ├───────────────┤ │ │ OpenClaw AI API │ +│ │ WP-Cron │ │ │ (via Mac Mini) │ +│ │ Agent Sched. │ │ │ │ +│ ├───────────────┤ │ └──────────────────────────┘ +│ │ AI Provider │ │ +│ │ (OpenClaw) │ │ +│ ├───────────────┤ │ +│ │ Nextcloud │ │ +│ │ Bridge │ │ +│ └───────────────┘ │ +│ │ +│ cPanel Git: │ +│ auto-pull from │ +│ Gitea on push │ +└──────────────────────┘ +``` + +## Data Flow: Content Generation (Ody Clone) + +``` +User/REST Client + │ + ▼ +POST https://ummah.falahos.my/wp-json/hermes/v1/content/generate + │ + ▼ +WordPress: rest_ensure_response() → HermesAiBridge\RestController + │ + ├──→ Validate Application Password (HTTP Basic Auth) + ├──→ Parse request: prompt, tone, length + │ + ▼ +HermesAiBridge\AiProvider + │ + ├──→ Call OpenClaw API (on Mac Mini or LLM provider) + ├──→ Handle response / error + │ + ▼ +Return generated content as JSON + │ + ▼ +WP-Cron (async) → HermesAiBridge\Scheduler + ├──→ Post to WordPress as draft + ├──→ Sync to Nextcloud + └──→ Log to database +``` + +## Data Flow: Auto-Reply (PI Clone — Planned) + +``` +bbPress Forum Topic / Comment + │ + ▼ +WordPress hook → HermesAiBridge\PiController + │ + ├──→ Analyze topic content + ├──→ Generate reply via AI Provider + │ + ▼ +Post reply as specified user + │ + ▼ +Notify thread participants (email/WhatsApp) +``` + +## Authentication Flow + +``` +HTTP Request + │ + ▼ +Cloudflare → ummah.falahos.my + │ (No WAF block — passes through) + ▼ +WordPress → Check Authorization header + │ + ├── Has "Basic base64(user:app_password)"? + │ └── Yes → WordPress validates Application Password + │ └── Valid → Process request + │ └── Invalid → HTTP 401 + │ + └── No HTTP Basic Auth? + └── REST API returns HTTP 401 +``` + +**Key insight:** Application Passwords authenticate at the WordPress application layer, not at the network layer. This means: +- Cloudflare WAF is transparent to them +- No special IP whitelisting needed +- Works from any IP, any network + +## Plugin Components + +### REST Controller (`rest-controller.php`) +- Registers `hermes/v1` namespace +- Routes: `content/generate`, `nextcloud/sync`, `settings` +- Authentication via `is_user_logged_in()` or Application Password + +### AI Provider (`ai-provider.php`) +- Connects to OpenClaw API +- Handles prompt formatting, response parsing +- Fallback: Curl-based HTTP client (no cURL extension needed) + +### Scheduler (`scheduler.php`) +- WP-Cron hooks for periodic tasks +- Content generation schedules +- Health check tasks + +### Nextcloud Bridge (`nextcloud-bridge.php`) +- WebDAV sync to `team.falahos.my` +- Uploads published content +- Syncs agent artifacts + +## Environment + +| Component | URL | Hosting | Purpose | +|-----------|-----|---------|---------| +| WordPress | ummah.falahos.my | cPanel (RoketServer) | Agent runtime | +| Gitea | git.falahos.my | Contabo Docker | Source + CI/CD | +| Nextcloud | team.falahos.my | Contabo Docker | Team hub | +| Gitea Runner | — | Contabo Docker | CI/CD execution | +| OpenClaw | 100.72.2.115:4747 | Mac Mini | AI inference | diff --git a/Cloudflare-WAF-Bypass-Discovery.md b/Cloudflare-WAF-Bypass-Discovery.md index e69de29..8f641e2 100644 --- a/Cloudflare-WAF-Bypass-Discovery.md +++ b/Cloudflare-WAF-Bypass-Discovery.md @@ -0,0 +1,90 @@ +# Cloudflare WAF Bypass Discovery 🎯 + +## The Breakthrough Finding + +We discovered that **Cloudflare WAF was NOT blocking the Contabo IP from the WordPress REST API**. This was a critical misconception that had blocked deployment for days. + +### What Actually Happened + +We assumed Cloudflare's WAF was blocking `172.17.0.1` (our Contabo Docker host) from reaching `ummah.falahos.my/wp-json/`. This assumption was wrong. + +**Evidence:** +``` +$ curl -s -w "HTTP %{http_code}" "https://ummah.falahos.my/wp-json/wp/v2/users" +HTTP 200 + +$ curl -s -w "HTTP %{http_code}" "https://ummah.falahos.my/wp-json/wp/v2/plugins" +HTTP 401 +``` + +The WP REST API was fully reachable — it just returned: +- **HTTP 200** for public endpoints (users, index, etc.) +- **HTTP 401** for protected endpoints (plugins, etc.) — **not a WAF block!** + +### Why We Thought It Was Blocked + +Earlier testing used `/wp-json/hermes/v1/content/generate` which returned HTTP 404 (plugin not installed yet, not blocked). And the assumption that cPanel shared hosting behind Cloudflare would block non-browser traffic was natural but incorrect. + +### The Real Blocker + +The actual blocker was **authentication**, not Cloudflare: + +``` +WP REST API needs → Application Password (HTTP Basic Auth) + → OR Cookie + Nonce (browser-based auth) +``` + +Cloudflare WAF was never the issue — we just needed a WordPress Application Password. + +## Solution: Application Passwords + +WordPress Application Passwords provide **app-layer authentication** via HTTP Basic Auth: + +```bash +curl -u "username:application_password" \ + "https://ummah.falahos.my/wp-json/wp/v2/plugins" +``` + +This bypasses any WAF because the auth happens at the application layer inside WordPress, not at the network level. + +### How to Create + +**Via REST API (if already logged in):** +```bash +# 1. Log in with cookie auth +curl -c cookies.txt \ + -d "log=wmj&pwd=PASSWORD&wp-submit=Log+In" \ + "https://ummah.falahos.my/wp-login.php" + +# 2. Extract nonce from admin page +NONCE=$(curl -b cookies.txt \ + "https://ummah.falahos.my/wp-admin/profile.php" \ + | grep -oP '"nonce":"[^"]*"' | head -1 | cut -d'"' -f4) + +# 3. Create Application Password +curl -b cookies.txt \ + -H "X-WP-Nonce: $NONCE" \ + -H "Content-Type: application/json" \ + -d '{"name":"my-agent"}' \ + "https://ummah.falahos.my/wp-json/wp/v2/users/me/application-passwords" +``` + +**Via Admin UI:** +1. Log in to `https://ummah.falahos.my/wp-admin` +2. Go to Users → Profile +3. Scroll to "Application Passwords" section +4. Enter a name and click "Add New" +5. Copy the generated password + +## Key Takeaway + +**Always verify assumptions about network-level blocking** before engineering complex workarounds. Test with `curl -w "HTTP %{http_code}"` first to distinguish between: +- HTTP 403/503 → WAF or server block +- HTTP 401 → Authentication needed (WordPress is responding!) +- HTTP 404 → Endpoint not found (plugin not installed) + +## Related + +- WordPress Application Passwords plugin is already installed on ummah.falahos.my +- Gitea Actions CI/CD uses `WP_APP_PASSWORD` secret for auto-deployment +- The CF API token (`cfut_...`) has DNS:Edit + Zone:Read scopes but NOT WAF management diff --git a/Getting-Started.md b/Getting-Started.md new file mode 100644 index 0000000..39b1025 --- /dev/null +++ b/Getting-Started.md @@ -0,0 +1,78 @@ +# Getting Started + +This guide covers everything you need to develop and deploy the Hermes cPanel Agent. + +## Prerequisites + +- Gitea account with push access to `wmj/hermes-cpanel-agent` +- WordPress admin access to `ummah.falahos.my` +- (For CI/CD) cPanel Git SSH key + +## Development Setup + +```bash +# Clone the repo +git clone https://git.falahos.my/wmj/hermes-cpanel-agent.git +cd hermes-cpanel-agent + +# All PHP files — no build step needed +# Install WordPress locally for testing, or use the staging site +``` + +## Plugin Structure + +``` +hermes-cpanel-agent/ +├── hermes-ai-bridge.php # Main plugin (WordPress header) +├── includes/ +│ ├── class-autoloader.php # PSR-4 autoloader +│ ├── core.php # Bootstrap + hooks +│ ├── installer.php # Activation/deactivation +│ ├── rest-controller.php # REST API: hermes/v1/* +│ ├── ai-provider.php # OpenClaw AI integration +│ ├── scheduler.php # WP-Cron tasks +│ └── nextcloud-bridge.php # Nextcloud sync +├── assets/ +│ └── admin.css +└── .gitea/ + ├── workflows/ # CI/CD pipelines + └── scripts/ # Helper scripts +``` + +## Security Rules + +NEVER use these in plugin code (cPanel blocks them anyway): +```php +exec(), shell_exec(), system(), passthru(), +popen(), proc_open(), eval(), assert() +``` + +## Making Changes + +1. Branch from `main` +2. Make changes +3. Push and open PR +4. CI runs: PHP lint, security scan, schema validation +5. Merge → auto-deploys via Gitea Actions + +## API Key Setup + +The plugin needs an OpenClaw API key configured via WP Admin: +1. Go to Settings → Hermes AI Bridge +2. Enter OpenClaw API key +3. Save + +Or via REST API: +```bash +curl -X PATCH -u "wmj:APP_PASSWORD" \ + -H "Content-Type: application/json" \ + -d '{"openclaw_api_key":"..."}' \ + "https://ummah.falahos.my/wp-json/hermes/v1/settings" +``` + +## Troubleshooting + +- **HTTP 401**: Need valid Application Password +- **HTTP 403 Nonce**: Cookie session expired — re-login +- **HTTP 404**: Endpoint not deployed — check plugin is active +- **Plugin not found**: Check `/wp-admin/plugins.php` — manually activate diff --git a/Gitea-Actions-CICD.md b/Gitea-Actions-CICD.md new file mode 100644 index 0000000..678ffe7 --- /dev/null +++ b/Gitea-Actions-CICD.md @@ -0,0 +1,140 @@ +# Gitea Actions CI/CD + +Full CI/CD pipeline documentation for the Hermes cPanel Agent. + +## Runner + +A Gitea Actions runner is deployed as a Docker Swarm service on Contabo: + +| Detail | Value | +|--------|-------| +| Name | `contabo-swarm-runner` | +| Host | Docker Swarm leader (`vmi3361598`) | +| Image | `gitea/act_runner:v0.6.1` | +| Network | `gitea_gitea-net` | +| Labels | `ubuntu-latest`, `self-hosted` | + +### Runner Setup + +```bash +# Get registration token from Gitea CLI +docker exec -u git gitea_gitea.1.xxx gitea actions generate-runner-token + +# Deploy as Swarm service +docker service create \ + --name gitea-runner \ + --network gitea_gitea-net \ + --restart-condition any \ + --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ + --env GITEA_INSTANCE_URL=https://git.falahos.my \ + --env GITEA_RUNNER_REGISTRATION_TOKEN=TOKEN \ + --env GITEA_RUNNER_NAME=contabo-swarm-runner \ + gitea/act_runner:latest +``` + +## Workflows + +### 1. CI (`ci.yml`) +**Trigger:** Push to main/develop, PRs + +``` +┌─────────────┐ ┌──────────────┐ ┌─────────────┐ +│ PHP Syntax │ → │ Security │ → │ Schema │ +│ Check │ │ Scan │ │ Validation │ +└─────────────┘ └──────────────┘ └─────────────┘ +``` + +- `php -l` on all PHP files +- Greps for banned functions (`exec`, `shell_exec`, `system`, `eval`) +- Validates WordPress plugin headers +- Verifies REST namespace declaration + +### 2. Deploy (`deploy.yml`) +**Trigger:** Push to main + +``` +┌──────────┐ ┌─────────────────┐ ┌──────────────┐ +│ CI Check │ → │ Git Push to │ → │ WP REST API │ +│ (pass) │ │ cPanel Remote │ │ Fallback │ +└──────────┘ └─────────────────┘ └──────────────┘ + ↓ + ┌──────────────┐ + │ Verify │ + │ Deployment │ + └──────────────┘ +``` + +**Primary path:** SSH into cPanel Git remote, force-push main branch. +**Fallback:** Build plugin zip and upload via WP REST API `/wp/v2/plugins`. +**Verification:** Check plugin is active + `hermes/v1` namespace is registered. + +### 3. Sync (`sync.yml`) +**Trigger:** Push to main + every 6 hours +- Syncs code to cPanel git +- Uploads plugin zip to Nextcloud artifacts folder + +### 4. Health (`health.yml`) +**Trigger:** Every 30 minutes +- Checks plugin is active on WordPress +- Verifies REST API responds +- Alerts on failure via Gitea notifications + +## Secrets + +Set these in **Settings → Actions → Secrets**: + +| Secret | Purpose | Required | +|--------|---------|----------| +| `WP_URL` | WordPress site URL | ✅ Set | +| `WP_APP_USER` | WordPress username | ✅ Set | +| `WP_APP_PASSWORD` | Application Password | ❌ Pending | +| `CPANEL_SSH_KEY` | cPanel deploy SSH key | ❌ Pending | +| `CPANEL_GIT_REMOTE` | cPanel git remote URL | ❌ Pending | +| `CPANEL_HOST` | cPanel SSH hostname | ❌ Pending | +| `CPANEL_DEPLOY_HOOK_URL` | Optional deploy webhook | Optional | +| `NEXTCLOUD_HERMES_PASS` | Nextcloud sync password | ❌ Pending | + +### Setting Secrets via API + +```bash +curl -X PUT -u "wmj:Abedib%4099" \ + -H "Content-Type: application/json" \ + -d '{"data":"BASE64_ENCODED_VALUE"}' \ + "https://git.falahos.my/api/v1/repos/wmj/hermes-cpanel-agent/actions/secrets/SECRET_NAME" +``` + +## Architecture + +``` +Developer Push + ↓ +Gitea (git.falahos.my) + ↓ +Gitea Actions Runner (Docker Swarm on Contabo) + ├── CI: lint, security, schema + ├── Deploy: git push → cPanel OR WP REST API + ├── Sync: cPanel sync + Nextcloud + └── Health: every 30min + ↓ +cPanel Hosting (ummah.falahos.my) + ├── cPanel Git Version Control (auto-pull) + ├── WordPress + Hermes Plugin + └── WP-Cron agent scheduler + ↓ +Agents Running: + ├── Ody Clone: Content Generator (REST API) + └── PI Clone: Auto-Reply (planned) +``` + +## Adding a New Workflow + +1. Create `.gitea/workflows/your-workflow.yml` +2. Use `runs-on: ubuntu-latest` (handled by our self-hosted runner) +3. Any helper scripts go in `.gitea/scripts/` +4. Push to main — runner picks it up automatically + +## Monitoring + +- Check runner status: `docker service logs gitea-runner --tail 20` +- View runs: https://git.falahos.my/wmj/hermes-cpanel-agent/actions +- Health checks: every 30 min, reports in Gitea Actions tab diff --git a/Home.md b/Home.md new file mode 100644 index 0000000..0f1e0b1 --- /dev/null +++ b/Home.md @@ -0,0 +1,22 @@ +# Hermes cPanel Agent Wiki + +Welcome to the Hermes cPanel Agent wiki — documentation for running AI agent clones (Ody, PI) on cPanel via a WordPress plugin with Gitea Actions CI/CD. + +## Pages + +- **[Cloudflare WAF Bypass Discovery](Cloudflare-WAF-Bypass-Discovery)** — How we discovered Cloudflare wasn't actually blocking the WP REST API +- **[Getting Started](Getting-Started)** — Setup guide for new developers +- **[Gitea Actions CI/CD](Gitea-Actions-CICD)** — Full CI/CD pipeline documentation +- **[Architecture Overview](Architecture-Overview)** — System architecture and data flow + +## Quick Start + +1. Get a WordPress Application Password for `wmj` user +2. Set Gitea Actions secrets: `WP_APP_PASSWORD`, `CPANEL_SSH_KEY`, etc. +3. Push to `main` → Gitea Actions auto-deploys to cPanel +4. Verify: `curl -u "wmj:APP_PASS" https://ummah.falahos.my/wp-json/hermes/v1/content/generate` + +## Repo + +- Code: https://git.falahos.my/wmj/hermes-cpanel-agent +- Issues: https://git.falahos.my/wmj/hermes-cpanel-agent/issues