Pin the artifact actions on v3: v4 does not work on this instance
Some checks failed
check / check (push) Successful in 6s
Build and Deploy to Cloudflare Pages / build (push) Successful in 20s
probe / q1-upload-v3-node16 (push) Successful in 7s
probe / q2-upload-v3-node20 (push) Successful in 22s
probe / q3-build-for-roundtrip (push) Successful in 11s
Build and Deploy to Cloudflare Pages / deploy (push) Has been skipped
probe / q4-deploy-dryrun (push) Failing after 43s

Round 1 of the branch probes reproduced the main failure and localised it.
Observed commit-status output for 2d328e7:

    check / check                        success  10s
    Build and Deploy .../ build          failure  15s   <- reproduced
    Build and Deploy .../ deploy         skipped        <- if: guard working
    probe / p1-bare-alpine-checkout      failure   3s
    probe / p2-alpine-apk-checkout       success   5s
    probe / p3-alpine-apk-build          success  15s
    probe / p4-alpine-apk-upload         failure  11s
    probe / p5-node20alpine-checkout     success   8s
    probe / p6-node20slim-checkout       success  11s

Reading that:

- p1 vs p2: act_runner does not supply node for JavaScript actions, so the
  `apk add --no-cache nodejs git tar` prerequisite step is genuinely required
  and genuinely sufficient. checkout then runs on musl.
- p3: script/bootstrap and script/test complete inside the Actions container
  on the pinned alpine digest. The mandated image replacement was never the
  problem.
- p2 vs p4: the only difference is a trailing upload-artifact v4 step, and it
  is the difference between success and failure.
- p5/p6: musl is not the issue -- checkout runs on both musl and glibc images.

So what broke the deploy was not the image swap that everyone reviewed, it was
the v3 -> v4 artifact bump that nobody questioned. Gitea 1.25.4's artifact
backend and this runner do not serve the v4 protocol; the workflow used v3
before this issue and that is what worked.

The artifact actions therefore move back to the v3 line, still pinned by full
commit SHA, which satisfies the hash-pinning requirement this issue is actually
about. Both are the node20 builds rather than the node16 defaults, so nothing
depends on a node16 runtime:

- upload-artifact  -> c6a3b2bd (v3.2.2-node20)
- download-artifact -> ad191675 (v3.1.0-node20)

Round 2 probes: the two fallback v3 builds in case the node20 ones do not
resolve, plus a producer/consumer pair that rehearses the deploy job -- same
pinned node image, same pinned download action, same pinned wrangler version,
stopping short of `wrangler pages deploy` so it touches nothing external.
This commit is contained in:
2026-08-09 02:50:36 +00:00
parent 2d328e759b
commit 602fd609e7
2 changed files with 84 additions and 67 deletions

View File

@@ -54,9 +54,16 @@ jobs:
- name: Archive site - name: Archive site
run: tar -czf site.tar.gz public run: tar -czf site.tar.gz public
# v4 does not work on this Gitea Actions instance -- it is what
# broke the deploy in run 25. Measured on this branch: a job
# identical to this one but ending in upload-artifact v4 fails,
# while the same job without that step passes. So this stays on
# the v3 line, pinned, using the node20 build of it rather than
# the node16 default. Revisit when the artifact v4 protocol works
# here; tracked separately.
- name: Upload artifact - name: Upload artifact
# actions/upload-artifact v4.6.2, 2026-08-09 # actions/upload-artifact v3.2.2-node20, 2026-08-09
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 uses: actions/upload-artifact@c6a3b2bd78b3985e4b2f15397fec357f0fd808de
with: with:
name: site name: site
path: site.tar.gz path: site.tar.gz
@@ -74,9 +81,11 @@ jobs:
# node 20.20.2-bookworm, 2026-08-09 # node 20.20.2-bookworm, 2026-08-09
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5 image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
steps: steps:
# Must match the upload-artifact major above -- v4 artifacts and
# v3 artifacts are different protocols and do not interoperate.
- name: Download artifact - name: Download artifact
# actions/download-artifact v4.3.0, 2026-08-09 # actions/download-artifact v3.1.0-node20, 2026-08-09
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 uses: actions/download-artifact@ad191675b41f6a5b46da9a048cb6893812da158b
with: with:
name: site name: site

View File

@@ -3,9 +3,23 @@
# The Actions jobs/logs API is not readable by this account, so the only # 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 # available signal is the commit-status API, which reports one entry per
# *job*. This file therefore encodes the diagnosis as job topology: each job # *job*. This file therefore encodes the diagnosis as job topology: each job
# below isolates exactly one hypothesis about why the pinned-alpine build job # below isolates one hypothesis, and each shows up as its own status context,
# failed after 22s on main (run 25), and each shows up as its own status # so one push tests them all.
# context, so one push tests them all in parallel. #
# Round 1 result (commit 2d328e7), which is what these round 2 jobs follow up
# on:
#
# p1 bare alpine + checkout failure 3s
# p2 alpine + apk nodejs git tar + checkout success 5s
# p3 p2 + script/bootstrap + script/test + tar success 15s
# p4 p2 + upload-artifact v4 failure 11s
# p5 node:20-alpine + checkout success 8s
# p6 node:20-bookworm-slim + checkout success 11s
#
# So the pinned alpine image and the runner-prerequisite step are fine, the
# site build inside the Actions container is fine, and the thing that fails is
# actions/upload-artifact v4 -- the one step this issue changed protocol on.
# Round 2 checks which pinned v3 build works and rehearses the deploy job.
name: probe name: probe
on: on:
@@ -14,20 +28,9 @@ on:
- pin-deploy-refs-observable - pin-deploy-refs-observable
jobs: jobs:
# Control. If this passes, act_runner supplies its own node for JS actions # Fallback A: the exact v3 the workflow used before this issue (node16
# and the whole "install node first" theory is wrong. # runtime), pinned.
p1-bare-alpine-checkout: q1-upload-v3-node16:
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 runs-on: ubuntu-latest
container: container:
# alpine 3.21, 2026-02-28 # alpine 3.21, 2026-02-28
@@ -39,12 +42,36 @@ jobs:
- run: apk add --no-cache nodejs git tar - run: apk add --no-cache nodejs git tar
# actions/checkout v4.2.2, 2026-02-28 # actions/checkout v4.2.2, 2026-02-28
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- run: tar -czf probe-a.tar.gz hugo.toml
# actions/upload-artifact v3.2.1, 2026-08-09
- uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
with: with:
submodules: recursive name: probe-a
path: probe-a.tar.gz
# p2 plus the site build. Isolates script/bootstrap and script/test inside # Fallback B: same release, node20 runtime.
# the Actions container from the JS-action machinery. q2-upload-v3-node20:
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
- run: tar -czf probe-b.tar.gz hugo.toml
# actions/upload-artifact v3.2.1-node20, 2026-08-09
- uses: actions/upload-artifact@c24449f33cd45d4826c6702db7e49f7cdb9b551d
with:
name: probe-b
path: probe-b.tar.gz
# Producer half of the round-trip rehearsal: byte-for-byte the build job
# from deploy.yml.
q3-build-for-roundtrip:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
# alpine 3.21, 2026-02-28 # alpine 3.21, 2026-02-28
@@ -61,50 +88,31 @@ jobs:
- run: script/bootstrap - run: script/bootstrap
- run: script/test - run: script/test
- run: tar -czf site.tar.gz public - run: tar -czf site.tar.gz public
# actions/upload-artifact v3.2.2-node20, 2026-08-09
# p2 plus the artifact upload. This is the one step whose protocol changed - uses: actions/upload-artifact@c6a3b2bd78b3985e4b2f15397fec357f0fd808de
# 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: with:
name: probe4 name: site
path: probe4.tar.gz path: site.tar.gz
# Fallback image direction, measured rather than assumed: an image that # Consumer half: the deploy job with everything except the publish call.
# already carries node. # Same pinned node image, same pinned download action, same pinned
p5-node20alpine-checkout: # wrangler version -- it just prints wrangler's version instead of running
# `wrangler pages deploy`, so it touches nothing external and needs no
# token. This is as close to exercising the deploy job as is possible
# without actually deploying.
q4-deploy-dryrun:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: q3-build-for-roundtrip
container: container:
# node 20-alpine, 2026-08-09 # node 20.20.2-bookworm, 2026-08-09
image: node@sha256:fb4cd12c85ee03686f6af5362a0b0d56d50c58a04632e6c0fb8363f609372293 image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
defaults:
run:
shell: sh
steps: steps:
# actions/checkout v4.2.2, 2026-02-28 # actions/download-artifact v3.1.0-node20, 2026-08-09
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: actions/download-artifact@ad191675b41f6a5b46da9a048cb6893812da158b
with:
# The glibc control. If musl node is the problem, this passes where the name: site
# alpine jobs do not. - run: tar -xzf site.tar.gz
p6-node20slim-checkout: - run: test -f public/index.html
runs-on: ubuntu-latest # wrangler 4.120.0, 2026-08-09
container: - run: npm install -g wrangler@4.120.0
# node 20-bookworm-slim, 2026-08-09 - run: wrangler --version
image: node@sha256:2cf067cfed83d5ea958367df9f966191a942351a2df77d6f0193e162b5febfc0
steps:
# actions/checkout v4.2.2, 2026-02-28
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683