Skip to content
29 changes: 29 additions & 0 deletions .github/settings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Probot Settings App — https://github.com/repository-settings/app
# Syncs repository settings on push to the default branch.

repository:
has_issues: true
has_projects: false
has_wiki: false
has_downloads: false
default_branch: main
allow_squash_merge: true
allow_merge_commit: true
allow_rebase_merge: true
delete_branch_on_merge: true

branches:
- name: main
protection:
required_pull_request_reviews:
required_approving_review_count: 0
dismiss_stale_reviews: false
require_code_owner_reviews: false
required_status_checks:
strict: false
contexts: []
enforce_admins: false
restrictions: null
required_linear_history: false
allow_force_pushes: true
allow_deletions: true
10 changes: 4 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ on:
pull_request:
push:
branches-ignore: [main]
workflow_dispatch:

permissions:
contents: read
contents: write
pull-requests: write

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
cancel-in-progress: false

env:
NODE_ENV: test
Expand All @@ -35,8 +37,6 @@ jobs:
name: Validate
runs-on: ubuntu-latest
timeout-minutes: 10
environment:
name: production

steps:
- name: Checkout
Expand Down Expand Up @@ -106,8 +106,6 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
needs: validate
environment:
name: production

steps:
- name: Checkout
Expand Down
87 changes: 52 additions & 35 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name: Deploy
on:
push:
branches: [main]
pull_request:
types: [closed]
workflow_dispatch:
inputs:
dry_run:
Expand All @@ -15,7 +17,8 @@ on:
default: 'false'

permissions:
contents: read
contents: write
pull-requests: write

env:
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
Expand Down Expand Up @@ -47,6 +50,13 @@ jobs:
quality-gates:
name: Quality Gates
runs-on: ubuntu-latest
# Run on: direct push to main, merged PR to main, or manual workflow_dispatch.
# Closed-without-merge PRs are excluded by the merged == true check.
if: >
github.event_name == 'push' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' &&
github.event.pull_request.merged == true)
outputs:
commit_hash: ${{ steps.meta.outputs.commit_hash }}
deploy_time: ${{ steps.meta.outputs.deploy_time }}
Expand All @@ -59,14 +69,13 @@ jobs:
id: start
run: echo "started_at=$(date +%s)" >> "$GITHUB_OUTPUT"

- name: Guard — only deploy from main
if: github.event_name == 'push'
- name: Guard — verify valid merge to main
if: github.event_name == 'pull_request'
run: |
if [ "$GITHUB_REF" != "refs/heads/main" ]; then
echo "ERROR: Deploy triggered on non-main ref: $GITHUB_REF" >&2
exit 1
fi
echo "✅ Running on refs/heads/main"
echo "PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}"
echo "Merged into: ${{ github.event.pull_request.base.ref }}"
echo "Merge commit: ${{ github.event.pull_request.merge_commit_sha }}"
echo "✅ Valid merge to main confirmed — proceeding with quality gates"

- uses: actions/checkout@v4

Expand Down Expand Up @@ -151,22 +160,26 @@ Mode: \`${DEPLOY_MODE}\`
By: \`${{ github.actor }}\`"

# ---------------------------------------------------------------------------
# Job 2: Deploy to VPS — DISABLED
# Deployments are performed directly on the VPS by running deploy.sh.
# GitHub Actions must NEVER launch, restart, or host the bot.
# To deploy: SSH into the VPS and run: bash /var/www/html/Runewager/deploy.sh
# Job 2: Deploy to VPS — SSH into VPS and run deploy.sh
# Only triggers after quality gates pass on a valid PR merge to main.
# ---------------------------------------------------------------------------
deploy:
name: Deploy to VPS (DISABLED — run deploy.sh on VPS directly)
name: Deploy to VPS
runs-on: ubuntu-latest
needs: quality-gates
if: false # GitHub must never trigger VPS restarts or bot launches
if: needs.quality-gates.result == 'success'
environment:
name: production

env:
DEPLOY_PASS: ${{ secrets.DEPLOY_PASS }}

steps:
- uses: actions/checkout@v4

- name: Install sshpass (password SSH fallback)
run: sudo apt-get install -y sshpass

- name: Setup SSH
env:
SERVER_KEY: ${{ secrets.SERVER_KEY }}
Expand Down Expand Up @@ -221,29 +234,33 @@ By: \`${{ github.actor }}\`"
fi
"

- name: Deploy (git pull origin main only)
- name: Deploy via deploy.sh (with password fallback)
env:
SERVER_HOST: ${{ secrets.SERVER_HOST }}
SERVER_USER: ${{ secrets.SERVER_USER }}
run: |
ssh deploy_target "
set -e
cd /var/www/html/Runewager
git fetch origin main
git reset --hard origin/main
echo 'Updated to:' \$(git rev-parse --short HEAD)
"
DEPLOY_CMD="bash /var/www/html/Runewager/deploy.sh github"

- name: Install deps on VPS
run: |
ssh deploy_target "
cd /var/www/html/Runewager
npm ci --omit=dev
"

- name: Port-swap deploy (guarded, max 3 restarts)
run: |
ssh deploy_target "
chmod +x /var/www/html/Runewager/scripts/deploy-port-swap.sh || true
/var/www/html/Runewager/scripts/deploy-port-swap.sh || true
"
# First attempt: SSH with key
if ssh deploy_target "$DEPLOY_CMD"; then
echo "✅ Deployed via SSH key"
else
echo "⚠️ SSH key attempt failed — waiting 120 seconds before password retry…"
sleep 120

# Second attempt: password fallback via sshpass
if sshpass -p "$DEPLOY_PASS" ssh \
-o StrictHostKeyChecking=no \
-o ConnectTimeout=15 \
"${SERVER_USER}@${SERVER_HOST}" "$DEPLOY_CMD"; then
echo "✅ Deployed via password fallback"
else
echo "❌ Both SSH attempts failed — sending admin alert"
chmod +x scripts/notify-telegram.sh
./scripts/notify-telegram.sh "❌ Deploy failed — SSH could not connect to VPS after key + password retry. Manual intervention required."
exit 1
fi
fi

- name: Download deploy report from VPS
if: always()
Expand Down
Loading
Loading