# ----------------------------------------------------------------------------- # cameleer-website — Deploy under-construction placeholder # # MANUAL TRIGGER ONLY. Replaces the live cameleer.io docroot with a static # "back shortly" page. Recovery: trigger Actions → deploy → Run workflow on # the desired main commit. # # Shares the deploy-production concurrency group with deploy.yml so the two # workflows queue rather than race on the same docroot. # # This workflow does NOT run npm/astro. The placeholder is hand-authored # static HTML in placeholder/, deliberately decoupled from the main build so # it can ship even when the main build is broken (which is the worst case in # which a placeholder is needed). # # Required secrets (repo settings → Actions → Secrets): # SFTP_HOST, SFTP_USER, SFTP_PATH, SFTP_KEY, SFTP_KNOWN_HOSTS # PUBLIC_SALES_EMAIL # ----------------------------------------------------------------------------- name: deploy-placeholder on: workflow_dispatch: concurrency: group: deploy-production cancel-in-progress: false jobs: deploy: runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 - name: Substitute sales email into placeholder env: PUBLIC_SALES_EMAIL: ${{ secrets.PUBLIC_SALES_EMAIL }} run: | set -e : "${PUBLIC_SALES_EMAIL:?PUBLIC_SALES_EMAIL secret must be set}" sed -i "s|__SALES_EMAIL__|${PUBLIC_SALES_EMAIL}|g" placeholder/index.html if grep -q '__SALES_EMAIL__' placeholder/index.html; then echo "Token __SALES_EMAIL__ still present after substitution — refusing to ship." exit 1 fi - name: Configure SSH env: SFTP_KEY: ${{ secrets.SFTP_KEY }} SFTP_KNOWN_HOSTS: ${{ secrets.SFTP_KNOWN_HOSTS }} run: | set -e : "${SFTP_KEY:?SFTP_KEY secret must be set}" : "${SFTP_KNOWN_HOSTS:?SFTP_KNOWN_HOSTS secret must be set}" mkdir -p ~/.ssh printf '%s\n' "$SFTP_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 printf '%s\n' "$SFTP_KNOWN_HOSTS" > ~/.ssh/known_hosts chmod 644 ~/.ssh/known_hosts if ! command -v rsync >/dev/null 2>&1 || ! command -v ssh >/dev/null 2>&1; then if command -v sudo >/dev/null 2>&1; then SUDO=sudo; else SUDO=; fi $SUDO apt-get update -qq $SUDO apt-get install -y --no-install-recommends rsync openssh-client fi - name: Deploy via rsync env: SFTP_USER: ${{ secrets.SFTP_USER }} SFTP_HOST: ${{ secrets.SFTP_HOST }} SFTP_PATH: ${{ secrets.SFTP_PATH }} run: | : "${SFTP_USER:?SFTP_USER secret must be set}" : "${SFTP_HOST:?SFTP_HOST secret must be set}" : "${SFTP_PATH:?SFTP_PATH secret must be set}" # Hetzner Webhosting splits SSH into two ports: # port 22 — SFTP only, no remote command exec # port 222 — full SSH with shell exec (rsync needs this) # `--rsync-path=/usr/bin/rsync` tells the local rsync where to find # the remote binary on Hetzner's locked-down PATH. # `BatchMode=yes` disables interactive prompts. rsync -avz --delete --rsync-path=/usr/bin/rsync \ -e "ssh -p 222 -i $HOME/.ssh/id_ed25519 -o BatchMode=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$HOME/.ssh/known_hosts" \ placeholder/ "$SFTP_USER@$SFTP_HOST:$SFTP_PATH/" - name: Post-deploy smoke test run: | set -e echo "Confirming the placeholder is live on www.cameleer.io..." BODY=$(curl -sf https://www.cameleer.io/) echo "$BODY" | grep -qF 'Routes are remapping' \ || { echo "Sentinel string missing — placeholder did not land."; exit 1; } echo "$BODY" | grep -qF 'mailto:' \ || { echo "mailto: link missing — sales email substitution may have failed."; exit 1; } curl -sfI https://www.cameleer.io/cameleer-logo.png > /dev/null \ || { echo "cameleer-logo.png not reachable on the live origin."; exit 1; } echo "Placeholder is live."