Full Gitea Actions CI/CD with cPanel git deployment
CI - Test & Lint / lint (push) Failing after 1m11s
CI - Test & Lint / test-schema (push) Failing after 8s
🚀 Deploy to cPanel via Git / ci-check (push) Failing after 8s
🚀 Deploy to cPanel via Git / deploy-to-cpanel (push) Has been skipped
🚀 Deploy to cPanel via Git / deploy-fallback (push) Has been skipped
🚀 Deploy to cPanel via Git / verify (push) Has been skipped
🌊 Sync cPanel Git + WordPress / sync-cpanel (push) Failing after 9s
CI - Test & Lint / security (push) Successful in 1m42s
🌊 Sync cPanel Git + WordPress / sync-nextcloud (push) Failing after 10s

- CI workflow: PHP lint, security scan, schema validation
- Deploy workflow: SSH -> cPanel git push + WP REST API fallback + verify
- Sync workflow: cPanel sync + Nextcloud artifact upload
- Health workflow: every 30min plugin health check
- Scripts: verify-deploy, deploy-report, check-namespace, health-check, setup-secrets
- README with full architecture documentation
- Gitea Actions runner registered on Docker Swarm (contabo-swarm-runner)
This commit is contained in:
2026-07-03 08:56:15 +02:00
parent 17d218c3b6
commit f620c65794
10 changed files with 563 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
name: CI - Test & Lint
on:
pull_request:
branches: [main, develop]
push:
branches: [main, develop]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: PHP Syntax Check
run: |
ERR=0
while IFS= read -r f; do
php -l "$f" || ERR=1
done < <(find . -name "*.php" -not -path "./.gitea/*")
exit $ERR
- name: Check for banned functions
run: |
BANNED="exec\|shell_exec\|system\|passthru\|popen\|proc_open\|eval\|assert\|pcntl_fork"
if grep -rn "$BANNED" --include="*.php" . 2>/dev/null | grep -v "BANNED="; then
echo "FAILED: Banned function found!"
exit 1
fi
echo "OK: No banned functions — safe for RoketServer cPanel"
- name: Validate WP plugin headers
run: |
for HEADER in "Plugin Name" "Version" "Description" "Author"; do
grep -q "$HEADER:" hermes-ai-bridge.php || { echo "Missing: $HEADER"; exit 1; }
done
echo "OK: All required plugin headers present"
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Scan for hardcoded secrets
run: |
# Check for accidental credential commits
if grep -rn "password\|secret\|api_key\|auth_token" --include="*.php" \
--include="*.json" . 2>/dev/null | grep -v "WP_APP_PASSWORD\|get_option\|secrets\.\|noreply"; then
echo "WARNING: Possible secrets in code:"
grep -rn "password\|secret\|api_key\|auth_token" --include="*.php" \
--include="*.json" . | grep -v "WP_APP_PASSWORD\|get_option\|secrets\.\|noreply"
fi
echo "OK: Secret scan complete"
- name: Check file permissions
run: |
find . -perm /o+w -not -path "./.git/*" -not -path "./.gitea/*" \
-not -path "./.github/*" 2>/dev/null | while read f; do
echo "WARNING: World-writable: $f"
done
test-schema:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify REST API namespace is declared
run: |
if grep -q "namespace.*hermes/v1" includes/rest-controller.php; then
echo "OK: REST namespace hermes/v1 found"
else
echo "FAILED: REST namespace hermes/v1 missing"
exit 1
fi
- name: Verify autoloader loads all classes
run: |
for CLASS in Core Installer RestController AiProvider Scheduler NextcloudBridge; do
if grep -q "$CLASS" includes/class-autoloader.php; then
echo "OK: $CLASS mapped in autoloader"
else
echo "FAILED: $CLASS not in autoloader"
exit 1
fi
done
+115
View File
@@ -0,0 +1,115 @@
name: 🚀 Deploy to cPanel via Git
on:
push:
branches: [main]
workflow_dispatch:
jobs:
ci-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: PHP Lint
run: |
ERROR=0
for f in $(find . -name "*.php" -not -path "./.gitea/*"); do
php -l "$f" || ERROR=1
done
exit $ERROR
- name: Security scan
run: |
if grep -rn "exec\|shell_exec\|system\|passthru\|eval\|assert" \
--include="*.php" . | grep -v "BANNED=\|_exec\|exec_\|get_option"; then
echo "FAILED: Banned function found!"
exit 1
fi
echo "OK: Security check passed"
deploy-to-cpanel:
needs: [ci-check]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup SSH for cPanel Git
env:
CPANEL_SSH_KEY: ${{ secrets.CPANEL_SSH_KEY }}
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "$CPANEL_SSH_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H "${{ secrets.CPANEL_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null
- name: Push to cPanel Git
env:
CPANEL_GIT_REMOTE: ${{ secrets.CPANEL_GIT_REMOTE }}
run: |
git remote add cpanel "$CPANEL_GIT_REMOTE"
git push cpanel main --force
echo "OK: Pushed to $CPANEL_GIT_REMOTE"
- name: Trigger cPanel deploy hook
env:
CPANEL_DEPLOY_HOOK: ${{ secrets.CPANEL_DEPLOY_HOOK_URL }}
run: |
if [ -n "$CPANEL_DEPLOY_HOOK" ]; then
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
"$CPANEL_DEPLOY_HOOK" --max-time 10)
echo "Hook returned HTTP $HTTP_CODE"
else
echo "No hook — cPanel Git auto-deploy handles it"
fi
deploy-fallback:
needs: [ci-check]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build plugin zip
run: |
mkdir -p build/hermes-cpanel-agent
cp hermes-ai-bridge.php build/hermes-cpanel-agent/
cp -r includes assets build/hermes-cpanel-agent/
cd build && zip -r ../hermes-cpanel-agent.zip hermes-cpanel-agent/
- name: Deploy via WP REST API (fallback)
env:
WP_URL: ${{ secrets.WP_URL }}
WP_APP_USER: ${{ secrets.WP_APP_USER }}
WP_APP_PASSWORD: ${{ secrets.WP_APP_PASSWORD }}
run: |
PLUGIN_ZIP=$(base64 -w0 hermes-cpanel-agent.zip)
RESP=$(curl -s -w "\n%{http_code}" -X POST \
"$WP_URL/wp-json/wp/v2/plugins" \
-H "Content-Type: application/json" \
-u "$WP_APP_USER:$WP_APP_PASSWORD" \
-d "{\"slug\":\"hermes-cpanel-agent\",\"status\":\"active\",\"source\":\"data:application/zip;base64,$PLUGIN_ZIP\"}")
HTTP_CODE=$(echo "$RESP" | tail -1)
BODY=$(echo "$RESP" | head -n -1)
echo "WP REST API: HTTP $HTTP_CODE"
echo "$BODY" | python3 .gitea/scripts/deploy-report.py
verify:
needs: [deploy-to-cpanel, deploy-fallback]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify plugin deployment
env:
WP_URL: ${{ secrets.WP_URL }}
WP_APP_USER: ${{ secrets.WP_APP_USER }}
WP_APP_PASSWORD: ${{ secrets.WP_APP_PASSWORD }}
run: |
curl -s "$WP_URL/wp-json/wp/v2/plugins" \
-u "$WP_APP_USER:$WP_APP_PASSWORD" | python3 .gitea/scripts/verify-deploy.py
- name: Verify hermes/v1 namespace
env:
WP_URL: ${{ secrets.WP_URL }}
run: |
curl -s "$WP_URL/wp-json" | python3 .gitea/scripts/check-namespace.py
+34
View File
@@ -0,0 +1,34 @@
name: 🩺 Health Check - cPanel Agent
on:
schedule:
- cron: '*/30 * * * *' # Every 30 minutes
workflow_dispatch:
jobs:
health:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check Plugin Status via WordPress
env:
WP_URL: ${{ secrets.WP_URL }}
WP_APP_USER: ${{ secrets.WP_APP_USER }}
WP_APP_PASSWORD: ${{ secrets.WP_APP_PASSWORD }}
run: |
curl -s "$WP_URL/wp-json/wp/v2/plugins" \
-u "$WP_APP_USER:$WP_APP_PASSWORD" | python3 .gitea/scripts/health-check.py
- name: Check REST API Endpoints
env:
WP_URL: ${{ secrets.WP_URL }}
run: |
# Try the hermes/v1 namespace
curl -s -o /dev/null -w "HTTP %{http_code}" "$WP_URL/wp-json/hermes/v1/content/generate" || echo "Endpoint check done"
- name: Notify on Failure
if: failure()
uses: actions/gitea-release-notify@v1
with:
title: "⚠️ cPanel Agent Health Check Failed"
body: "The health check for hermes-cpanel-agent on ummah.falahos.my failed. Check the Gitea Actions run for details."
+48
View File
@@ -0,0 +1,48 @@
name: 🌊 Sync cPanel Git + WordPress
on:
push:
branches: [main]
schedule:
- cron: '0 */6 * * *' # Every 6 hours: ensure cPanel is in sync
jobs:
sync-cpanel:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Sync to cPanel Git
env:
CPANEL_GIT_REMOTE: ${{ secrets.CPANEL_GIT_REMOTE }}
CPANEL_SSH_KEY: ${{ secrets.CPANEL_SSH_KEY }}
run: |
mkdir -p ~/.ssh
echo "$CPANEL_SSH_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H "${{ secrets.CPANEL_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null
git remote add cpanel "$CPANEL_GIT_REMOTE"
git push cpanel main --force
echo "✅ Synced to cPanel git"
sync-nextcloud:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build plugin for Nextcloud sync
run: |
mkdir -p build
zip -r hermes-cpanel-agent.zip hermes-ai-bridge.php includes assets
- name: Upload to Nextcloud
env:
NC_URL: "https://team.falahos.my"
NC_USER: "hermes"
NC_PASS: ${{ secrets.NEXTCLOUD_HERMES_PASS }}
run: |
# Upload plugin zip to Nextcloud team folder
curl -s -u "$NC_USER:$NC_PASS" \
-T hermes-cpanel-agent.zip \
"$NC_URL/remote.php/dav/files/hermes/Agent%20Artifacts/hermes-cpanel-agent.zip"
echo "✅ Uploaded to Nextcloud"