name: Deploy on: workflow_run: workflows: ["CI"] types: [completed] branches: [main] workflow_dispatch: permissions: contents: read concurrency: group: deploy cancel-in-progress: true env: VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }} VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }} VITE_DEPOSIT_TON_ADDRESS: ${{ secrets.VITE_DEPOSIT_TON_ADDRESS }} VITE_DEPOSIT_POLKADOT_ADDRESS: ${{ secrets.VITE_DEPOSIT_POLKADOT_ADDRESS }} jobs: deploy: name: Deploy to VPS runs-on: ubuntu-latest if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20' cache: 'npm' - run: npm ci - run: npm run build - name: Deploy to telegram.pezkiwi.app env: DEPLOY_KEY: ${{ secrets.MINIAPP_SITE_DEPLOY_KEY }} # VPS3's host key, read from the host itself; any other key fails. KNOWN_HOST: "217.77.6.126 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMxxRmMEYyng+B9O3jcUCMnUa31SyWQ+l7aj18/soWtJ" run: | umask 077 printf '%s\n' "$DEPLOY_KEY" > "$RUNNER_TEMP/deploy_key" printf '%s\n' "$KNOWN_HOST" > "$RUNNER_TEMP/known_hosts" # The key is pinned on the host to ops/host/miniapp-site-receive # (authorized_keys restrict,command=): the site tar on stdin, then the # cleanup of earlier deploys' assets; nothing else. tar -C dist -cf - . | ssh -i "$RUNNER_TEMP/deploy_key" -o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile="$RUNNER_TEMP/known_hosts" miniapp-deploy@217.77.6.126 deploy # Edge functions live in a Supabase volume shared with other projects, so they # are written through the ownership gate on the host rather than copied in # directly. The gate refuses any name this project does not own, which is what # stops a repeat of the 2026-06-28 incident where another project's deploy # silently replaced telegram-auth and broke sign-in for a month. deploy-functions: name: Deploy edge functions (self-hosted) needs: deploy runs-on: ubuntu-latest steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 # telegram-bot and ask are excluded on purpose: both Telegram bots and the # news.pex.mom assistant are served from the cloud project, not from here. # Stale copies of both still sit in this volume from before that split and # take no traffic. They are deployed by the deploy-cloud-functions job. - name: Package functions run: | tar czf functions.tgz -C supabase \ --exclude='functions/telegram-bot' \ --exclude='functions/ask' \ functions # The ownership gate and its registry guard every project's functions # in the shared volume, so this deploy does not install them; root does, # from ops/ here. What the deploy does is refuse to run when the host's # copy is not the one in this repository. - name: Deploy through ownership gate env: DEPLOY_KEY: ${{ secrets.MINIAPP_FUNCTIONS_DEPLOY_KEY }} # VPS3's host key, read from the host itself; any other key fails. KNOWN_HOST: "217.77.6.126 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMxxRmMEYyng+B9O3jcUCMnUa31SyWQ+l7aj18/soWtJ" run: | umask 077 printf '%s\n' "$DEPLOY_KEY" > "$RUNNER_TEMP/deploy_key" printf '%s\n' "$KNOWN_HOST" > "$RUNNER_TEMP/known_hosts" # The key is pinned on the host to ops/host/miniapp-functions-ssh. want="$(sha256sum ops/supabase-deploy-functions ops/functions-registry.json | awk '{print $1}')" have="$(ssh -i "$RUNNER_TEMP/deploy_key" -o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile="$RUNNER_TEMP/known_hosts" miniapp-deploy@217.77.6.126 gate-sha)" if [ "$want" != "$have" ]; then echo "::error::the host's ownership gate or registry is not the one in ops/; install them as root (ops/host/README.md), then re-run" exit 1 fi ssh -i "$RUNNER_TEMP/deploy_key" -o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile="$RUNNER_TEMP/known_hosts" miniapp-deploy@217.77.6.126 deploy < functions.tgz # The two Telegram bots and the news.pex.mom assistant run on the cloud # Supabase project, reached by webhook at # vbhftvdayqfmcgmzdxfv.supabase.co/functions/v1/telegram-bot?bot=krd|dks. # These were deployed by hand for months, which let the source in git drift # behind what was actually running — badly enough that on 2026-07-21 the live # function body had to be pulled back out of the deployed bundle to recover it. deploy-cloud-functions: name: Deploy edge functions (cloud) needs: deploy runs-on: ubuntu-latest steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Deploy telegram-bot and ask env: SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} run: | set -e if [ -z "$SUPABASE_ACCESS_TOKEN" ]; then echo "::error::SUPABASE_ACCESS_TOKEN is not set — the bots would silently keep running old code" exit 1 fi for fn in telegram-bot ask; do npx --yes supabase@latest functions deploy "$fn" \ --project-ref vbhftvdayqfmcgmzdxfv \ --no-verify-jwt done