static-site-deploy/README.md
Eric Wendland 411010ef5a
All checks were successful
Test / test (push) Successful in 8s
feat: coordinate static site deployments through Gandalf
2026-07-21 23:26:34 +02:00

2.7 KiB

Static Site Deploy

A small, dependency-free Forgejo Action that synchronizes a completed static website build to a dedicated Bunny Storage Zone.

The runner needs Bash and Python 3.11 or newer. The action itself installs no packages and executes no code from the Gandalf repository.

The deployer requires index.html, rejects symbolic links, compares files with a checksum manifest, uploads changed assets before HTML, deletes stale files only after successful uploads, and publishes the new manifest last.

Forgejo Actions

Store the website-specific Storage Zone password as the repository secret BUNNY_STORAGE_PASSWORD, then pin the action to an immutable commit from the public action repository:

---
name: Deploy website

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: docker
    steps:
      - uses: https://data.forgejo.org/actions/checkout@v6
      - run: npm ci
      - run: npm run build
      - name: Deploy to Bunny
        uses: https://forge.tionis.dev/actions/static-site-deploy@<commit-sha>
        with:
          directory: dist
          storage-zone: example-org
          purge-endpoint: https://gandalf.tionis.dev
        env:
          BUNNY_STORAGE_PASSWORD: ${{ secrets.BUNNY_STORAGE_PASSWORD }}

Only run deployments for trusted branches. A contributor able to change a workflow that receives production secrets can attempt to expose those secrets.

purge-endpoint is the backward-compatible name of the optional Gandalf deployment gateway input. Before uploading, the action acquires an expiring per-zone lease. After publishing the manifest, Gandalf verifies its SHA-256 digest, records the revision and deployment outcome, and purges the mapped Pull Zones only when the manifest changed from the previous successful deployment. Interrupted uploads are aborted best-effort; abandoned leases expire after 30 minutes. The dedicated Storage Zone password authorizes this workflow without exposing an account-wide API key to the project.

Command line

The script can also be used directly with Python 3.11 or newer:

export BUNNY_STORAGE_ZONE=example-org
export BUNNY_STORAGE_PASSWORD='zone-specific password'
python3 static_site.py bunny dist --dry-run
python3 static_site.py bunny dist

Changed files are transferred with 16 workers by default while preserving the asset-before-HTML and manifest-last publication order. Set BUNNY_TRANSFER_WORKERS or pass --workers to tune the limit.

Set BUNNY_STORAGE_ENDPOINT when the Storage Zone is outside Frankfurt.

Development

python3 -m unittest discover -s tests

The canonical source lives in the private Gandalf infrastructure repository and is published to this repository as a Git subtree.