deploy #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: deploy | |
| on: | |
| push: | |
| branches: [master] | |
| workflow_dispatch: | |
| concurrency: | |
| group: deploy-x402 | |
| cancel-in-progress: false | |
| jobs: | |
| verify: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| - run: npm ci | |
| - run: npm run typecheck | |
| - run: npm test | |
| build-and-push: | |
| needs: verify | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| outputs: | |
| image_tag: ${{ steps.meta.outputs.tag }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - id: meta | |
| run: | | |
| short_sha="${GITHUB_SHA::7}" | |
| owner_lc="${GITHUB_REPOSITORY_OWNER,,}" | |
| echo "tag=sha-${short_sha}" >> "$GITHUB_OUTPUT" | |
| echo "owner=${owner_lc}" >> "$GITHUB_OUTPUT" | |
| - uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| push: true | |
| # GHCR rejects uppercase repo paths, so the image lives under the | |
| # lowercased owner regardless of how the repo is spelled. | |
| tags: | | |
| ghcr.io/${{ steps.meta.outputs.owner }}/x402-aegent-dev:latest | |
| ghcr.io/${{ steps.meta.outputs.owner }}/x402-aegent-dev:${{ steps.meta.outputs.tag }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| deploy: | |
| needs: build-and-push | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: webfactory/ssh-agent@v0.9.0 | |
| with: | |
| ssh-private-key: ${{ secrets.DEPLOY_SSH_KEY }} | |
| - name: Add host to known_hosts | |
| run: | | |
| mkdir -p ~/.ssh | |
| ssh-keyscan -H "${{ secrets.DEPLOY_HOST }}" >> ~/.ssh/known_hosts | |
| - uses: actions/checkout@v4 | |
| - name: Bootstrap host directory + sync managed files | |
| env: | |
| USER_AT_HOST: ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} | |
| run: | | |
| # Idempotent bootstrap. Creates /srv/x402 if missing; the data | |
| # subdir holds sqlite WAL across deploys. Owned by the SSH user | |
| # so subsequent scp doesn't need sudo. | |
| ssh -o BatchMode=yes "$USER_AT_HOST" \ | |
| 'mkdir -p /srv/x402/data && chmod 755 /srv/x402' | |
| # Files in deploy/ are managed by CI — overwritten on every run. | |
| # .env is NOT in deploy/, so this never touches the host's secrets. | |
| scp -o BatchMode=yes \ | |
| deploy/docker-compose.yml \ | |
| deploy/deploy.sh \ | |
| deploy/x402.caddyfile \ | |
| "$USER_AT_HOST:/srv/x402/" | |
| - name: Verify .env exists, install Caddy site, and deploy | |
| env: | |
| USER_AT_HOST: ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} | |
| # Single SSH session that: | |
| # 1. Refuses to proceed if /srv/x402/.env is missing — secrets are | |
| # managed manually on the host, not by CI. | |
| # 2. chmods deploy.sh. | |
| # 3. Installs the Caddy snippet idempotently (only reloads Caddy | |
| # if the file actually changed). | |
| # 4. Runs the deploy script. | |
| run: | | |
| ssh -o BatchMode=yes "$USER_AT_HOST" 'bash -se' <<'REMOTE' | |
| set -euo pipefail | |
| if [ ! -f /srv/x402/.env ]; then | |
| echo "ERROR: /srv/x402/.env is missing on the host." >&2 | |
| echo "Create it from deploy/env.template before deploying:" >&2 | |
| echo " scp deploy/env.template <user>@<host>:/srv/x402/.env" >&2 | |
| echo " ssh <user>@<host> 'chmod 600 /srv/x402/.env && \$EDITOR /srv/x402/.env'" >&2 | |
| exit 1 | |
| fi | |
| chmod 700 /srv/x402/deploy.sh | |
| if ! cmp -s /srv/x402/x402.caddyfile /etc/caddy/conf.d/x402.caddyfile 2>/dev/null; then | |
| echo "Caddy snippet changed; installing and reloading." | |
| cp /srv/x402/x402.caddyfile /etc/caddy/conf.d/x402.caddyfile | |
| caddy validate --config /etc/caddy/Caddyfile | |
| systemctl reload caddy | |
| fi | |
| /srv/x402/deploy.sh | |
| REMOTE |