From 59e51dae99b68ca6e633e468864b1b6b1454d115 Mon Sep 17 00:00:00 2001 From: peptiderepo <273788462+peptiderepo@users.noreply.github.com> Date: Tue, 14 Apr 2026 16:53:19 +0700 Subject: [PATCH] ci: fix CTO reviewer + harden deploy ssh-keyscan (#3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: post CTO review as COMMENT instead of APPROVE GITHUB_TOKEN cannot formally approve PRs without a repo setting toggle. Verdict is still prominent in the first line of the review body, and the human merges based on reading it — no behavior loss. Agent-Session: cowork-reviewer-fix-20260414 * fix(ci): ssh-keyscan failure no longer fails the deploy ssh-keyscan was being called with set -e in effect and stderr suppressed, so a single keyscan failure killed the entire deploy with no diagnostic output. Since rsync/ssh use StrictHostKeyChecking=no, the known_hosts entry is not load-bearing — making the keyscan best-effort is safe. stderr is now captured to /tmp/keyscan.err and emitted as a warning so future failures are debuggable. Agent-Session: cowork-deploy-fix-20260414 --- .github/workflows/cto-review.yml | 15 +-- .github/workflows/deploy.yml | 183 ++++++++++++++++--------------- 2 files changed, 100 insertions(+), 98 deletions(-) diff --git a/.github/workflows/cto-review.yml b/.github/workflows/cto-review.yml index 89fb40f..9b97c24 100644 --- a/.github/workflows/cto-review.yml +++ b/.github/workflows/cto-review.yml @@ -224,25 +224,22 @@ jobs: PY - name: Post PR review + # Always posts as COMMENT — not APPROVE/REQUEST_CHANGES — because the default + # GITHUB_TOKEN is not permitted to formally approve PRs without toggling a + # repo setting. The verdict is still prominent in the first line of the body + # ("## CTO Review — APPROVE|REQUEST_CHANGES|COMMENT"). Human merges, so the + # GitHub-native review state isn't load-bearing. if: steps.claude.outputs.skipped != '1' uses: actions/github-script@v7 - env: - VERDICT: ${{ steps.claude.outputs.verdict }} with: script: | const fs = require('fs'); const body = fs.readFileSync('/tmp/review-body.md', 'utf8'); - const verdict = process.env.VERDICT; - const eventMap = { - 'APPROVE': 'APPROVE', - 'REQUEST_CHANGES': 'REQUEST_CHANGES', - 'COMMENT': 'COMMENT' - }; await github.rest.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number, - event: eventMap[verdict] || 'COMMENT', + event: 'COMMENT', body, }); diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 046563f..7512496 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,90 +1,95 @@ -name: Deploy Theme to Hostinger - -on: - push: - branches: [main] - -jobs: - validate: - name: Validate PHP & JS - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: PHP Lint Check - run: | - find . -name "*.php" -not -path "./vendor/*" -not -path "./node_modules/*" -exec php -l {} \; | (grep -v "No syntax errors" || true) | head -20 - test ${PIPESTATUS[0]} -eq 0 - - - name: Install PHPCS with WordPress standards - run: | - composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true - composer global require --dev squizlabs/php_codesniffer:"^3.0" wp-coding-standards/wpcs:"^3.0" phpcsstandards/phpcsutils:"^1.0" - - - name: Run PHPCS (WordPress Core) - run: | - ~/.composer/vendor/bin/phpcs -s . - - - name: JS Syntax Check - run: | - find assets/js -name "*.js" -exec node --check {} \; - - deploy: - needs: validate - name: Deploy to Production - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup SSH key - run: | - mkdir -p ~/.ssh - echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key - chmod 600 ~/.ssh/deploy_key - ssh-keyscan -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/dev/null - - - name: Deploy via rsync - run: | - rsync -avz --delete \ - --exclude='.git' \ - --exclude='.github' \ - --exclude='tests/' \ - --exclude='phpunit.xml' \ - --exclude='composer.json' \ - --exclude='composer.lock' \ - --exclude='vendor/' \ - --exclude='node_modules/' \ - --exclude='.phpcs.xml.dist' \ - -e "ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no" \ - ./ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/wp-content/themes/peptide-starter/ - - - name: Purge LiteSpeed Cache - run: | - ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no \ - ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} << 'ENDSSH' - CACHE_DIR="/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/wp-content/litespeed" - if [ -d "$CACHE_DIR" ]; then - rm -rf "$CACHE_DIR"/* - echo "LiteSpeed cache purged." - fi - touch "/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/.lscache_purge" 2>/dev/null || true - echo "Cache purge signal sent." - ENDSSH - - - name: Cleanup - if: always() - run: rm -f ~/.ssh/deploy_key - - - name: Health check - run: | - sleep 5 - STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://peptiderepo.com) - if [ "$STATUS" != "200" ]; then - echo "WARNING: Site returned HTTP $STATUS after deploy" - exit 1 - fi +name: Deploy Theme to Hostinger + +on: + push: + branches: [main] + +jobs: + validate: + name: Validate PHP & JS + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: PHP Lint Check + run: | + find . -name "*.php" -not -path "./vendor/*" -not -path "./node_modules/*" -exec php -l {} \; | (grep -v "No syntax errors" || true) | head -20 + test ${PIPESTATUS[0]} -eq 0 + + - name: Install PHPCS with WordPress standards + run: | + composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true + composer global require --dev squizlabs/php_codesniffer:"^3.0" wp-coding-standards/wpcs:"^3.0" phpcsstandards/phpcsutils:"^1.0" + + - name: Run PHPCS (WordPress Core) + run: | + ~/.composer/vendor/bin/phpcs -s . + + - name: JS Syntax Check + run: | + find assets/js -name "*.js" -exec node --check {} \; + + deploy: + needs: validate + name: Deploy to Production + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup SSH key + run: | + mkdir -p ~/.ssh + echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + # Best-effort: keyscan stderr captured for diagnosis but never fatal. + # We use StrictHostKeyChecking=no on the actual ssh/rsync calls anyway. + ssh-keyscan -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/tmp/keyscan.err || { + echo "::warning::ssh-keyscan failed (non-fatal). stderr:" + cat /tmp/keyscan.err || true + } + + - name: Deploy via rsync + run: | + rsync -avz --delete \ + --exclude='.git' \ + --exclude='.github' \ + --exclude='tests/' \ + --exclude='phpunit.xml' \ + --exclude='composer.json' \ + --exclude='composer.lock' \ + --exclude='vendor/' \ + --exclude='node_modules/' \ + --exclude='.phpcs.xml.dist' \ + -e "ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no" \ + ./ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/wp-content/themes/peptide-starter/ + + - name: Purge LiteSpeed Cache + run: | + ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT }} -o StrictHostKeyChecking=no \ + ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} << 'ENDSSH' + CACHE_DIR="/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/wp-content/litespeed" + if [ -d "$CACHE_DIR" ]; then + rm -rf "$CACHE_DIR"/* + echo "LiteSpeed cache purged." + fi + touch "/home/${{ secrets.SSH_USERNAME }}/domains/peptiderepo.com/public_html/.lscache_purge" 2>/dev/null || true + echo "Cache purge signal sent." + ENDSSH + + - name: Cleanup + if: always() + run: rm -f ~/.ssh/deploy_key + + - name: Health check + run: | + sleep 5 + STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://peptiderepo.com) + if [ "$STATUS" != "200" ]; then + echo "WARNING: Site returned HTTP $STATUS after deploy" + exit 1 + fi echo "Site is healthy (HTTP 200)" \ No newline at end of file