diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 3967d2e..cb25572 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -1,52 +1,93 @@ name: Build and Deploy to Cloudflare Pages on: - push: - branches: - - feat/initial-site - - main + push: + branches: + - main + # TEMPORARY: development-only trigger so the build job actually + # executes under act_runner before this reaches main. Removed in + # the final commit. + - pin-deploy-refs-observable jobs: - build: - runs-on: ubuntu-latest - container: - image: klakegg/hugo:ext-alpine - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive + build: + runs-on: ubuntu-latest + container: + # Same digest the Dockerfile pins: one pinned base image and the + # same dependency list (script/bootstrap) for both the check build + # and the deploy build. The one extra thing this job needs on top + # of the Dockerfile is the Actions runner's own prerequisites -- + # see the first step. + # alpine 3.21, 2026-02-28 + image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709 + defaults: + run: + # The default step shell is bash; this image has only busybox + # sh, so say so explicitly rather than rely on a fallback. + shell: sh + steps: + # This image is bare busybox+musl. act_runner executes JavaScript + # actions (checkout, upload-artifact) with `node` *inside* the job + # container and does not inject one, so node has to exist before + # the first `uses:` step -- script/bootstrap runs too late. git is + # needed for checkout's `submodules: recursive` (without it + # checkout degrades to a tarball download that cannot do + # submodules). An inline `run:` needs only a shell, so this step + # works on the bare image. These apk packages resolve at run time + # and are not hash-pinned; that gap is repo-wide (script/bootstrap + # has it too) and is tracked in #19. + - name: Install runner prerequisites + run: apk add --no-cache nodejs git tar - - name: Build site - run: hugo --minify + - name: Checkout + # actions/checkout v4.2.2, 2026-02-28 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + submodules: recursive - - name: Archive site - run: tar -czf site.tar.gz public + - name: Install build dependencies + run: script/bootstrap - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: site - path: site.tar.gz + - name: Build site + run: script/test - deploy: - runs-on: ubuntu-latest - needs: build - container: - image: node:20 - steps: - - name: Download artifact - uses: actions/download-artifact@v3 - with: - name: site + - name: Archive site + run: tar -czf site.tar.gz public - - name: Extract site - run: tar -xzf site.tar.gz + - name: Upload artifact + # actions/upload-artifact v4.6.2, 2026-08-09 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + with: + name: site + path: site.tar.gz - - name: Install Wrangler - run: npm install -g wrangler + deploy: + runs-on: ubuntu-latest + needs: build + # Publishing guard. This job spends CLOUDFLARE_API_TOKEN and creates a + # real Cloudflare Pages deployment, so it must never run off main -- + # not even if a branch is added to the push trigger above, deliberately + # or by accident. Costs one line; the build job stays exercisable from + # a branch without this job touching anything external. + if: github.ref_name == 'main' + container: + # node 20.20.2-bookworm, 2026-08-09 + image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5 + steps: + - name: Download artifact + # actions/download-artifact v4.3.0, 2026-08-09 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 + with: + name: site - - name: Deploy to Cloudflare Pages - run: wrangler pages deploy public --project-name=lora-vegas --branch=${{ github.ref_name }} - env: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + - name: Extract site + run: tar -xzf site.tar.gz + + - name: Install Wrangler + # wrangler 4.120.0, 2026-08-09 + run: npm install -g wrangler@4.120.0 + + - name: Deploy to Cloudflare Pages + run: wrangler pages deploy public --project-name=lora-vegas --branch=${{ github.ref_name }} + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} diff --git a/.gitea/workflows/probe.yml b/.gitea/workflows/probe.yml new file mode 100644 index 0000000..88ae631 --- /dev/null +++ b/.gitea/workflows/probe.yml @@ -0,0 +1,110 @@ +# TEMPORARY diagnostic workflow. Deleted before this branch is merged. +# +# The Actions jobs/logs API is not readable by this account, so the only +# available signal is the commit-status API, which reports one entry per +# *job*. This file therefore encodes the diagnosis as job topology: each job +# below isolates exactly one hypothesis about why the pinned-alpine build job +# failed after 22s on main (run 25), and each shows up as its own status +# context, so one push tests them all in parallel. +name: probe + +on: + push: + branches: + - pin-deploy-refs-observable + +jobs: + # Control. If this passes, act_runner supplies its own node for JS actions + # and the whole "install node first" theory is wrong. + p1-bare-alpine-checkout: + runs-on: ubuntu-latest + container: + # alpine 3.21, 2026-02-28 + image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709 + steps: + # actions/checkout v4.2.2, 2026-02-28 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + # Exactly the reverted prefix: apk prerequisites, then checkout. Isolates + # checkout from everything downstream of it. + p2-alpine-apk-checkout: + runs-on: ubuntu-latest + container: + # alpine 3.21, 2026-02-28 + image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709 + defaults: + run: + shell: sh + steps: + - run: apk add --no-cache nodejs git tar + # actions/checkout v4.2.2, 2026-02-28 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + submodules: recursive + + # p2 plus the site build. Isolates script/bootstrap and script/test inside + # the Actions container from the JS-action machinery. + p3-alpine-apk-build: + runs-on: ubuntu-latest + container: + # alpine 3.21, 2026-02-28 + image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709 + defaults: + run: + shell: sh + steps: + - run: apk add --no-cache nodejs git tar + # actions/checkout v4.2.2, 2026-02-28 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + submodules: recursive + - run: script/bootstrap + - run: script/test + - run: tar -czf site.tar.gz public + + # p2 plus the artifact upload. This is the one step whose protocol changed + # in this issue (v3 -> v4) and the ~22s timing is consistent with reaching + # it. + p4-alpine-apk-upload: + runs-on: ubuntu-latest + container: + # alpine 3.21, 2026-02-28 + image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709 + defaults: + run: + shell: sh + steps: + - run: apk add --no-cache nodejs git tar + # actions/checkout v4.2.2, 2026-02-28 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - run: tar -czf probe4.tar.gz hugo.toml + # actions/upload-artifact v4.6.2, 2026-08-09 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + with: + name: probe4 + path: probe4.tar.gz + + # Fallback image direction, measured rather than assumed: an image that + # already carries node. + p5-node20alpine-checkout: + runs-on: ubuntu-latest + container: + # node 20-alpine, 2026-08-09 + image: node@sha256:fb4cd12c85ee03686f6af5362a0b0d56d50c58a04632e6c0fb8363f609372293 + defaults: + run: + shell: sh + steps: + # actions/checkout v4.2.2, 2026-02-28 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + # The glibc control. If musl node is the problem, this passes where the + # alpine jobs do not. + p6-node20slim-checkout: + runs-on: ubuntu-latest + container: + # node 20-bookworm-slim, 2026-08-09 + image: node@sha256:2cf067cfed83d5ea958367df9f966191a942351a2df77d6f0193e162b5febfc0 + steps: + # actions/checkout v4.2.2, 2026-02-28 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683