Hash-pin every external reference in deploy.yml, verified on a real runner (closes #7) #22
@@ -4,10 +4,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- 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:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -54,14 +50,14 @@ 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
|
# v3, not v4: artifacts v4 is a different wire protocol and this
|
||||||
# broke the deploy in run 25. Measured on this branch: a job
|
# Gitea Actions instance does not serve it. That is what broke the
|
||||||
# identical to this one but ending in upload-artifact v4 fails,
|
# deploy in run 25 -- measured by running two otherwise identical
|
||||||
# while the same job without that step passes. So this stays on
|
# jobs on a branch, one ending in upload-artifact v4 (failed) and
|
||||||
# the v3 line, pinned, using the node20 build of it rather than
|
# one without that step (passed). Tracked in #20. This SHA is the
|
||||||
# here; tracked separately. This is the exact commit the mutable
|
# exact commit the mutable `@v3` used to resolve to, i.e. the code
|
||||||
# `@v3` used to resolve to, i.e. the code that was deploying this
|
# that was already deploying this site, now pinned rather than
|
||||||
# site before this issue -- now pinned instead of floating.
|
# floating.
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
# actions/upload-artifact v3.2.1, 2026-08-09
|
# actions/upload-artifact v3.2.1, 2026-08-09
|
||||||
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
|
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
|
||||||
@@ -102,9 +98,8 @@ jobs:
|
|||||||
# npm picks the newest version whose engines the running node
|
# npm picks the newest version whose engines the running node
|
||||||
# satisfies, which on node 20 is exactly 4.86.0. So this pins the
|
# satisfies, which on node 20 is exactly 4.86.0. So this pins the
|
||||||
# version that has actually been deploying this site, rather than
|
# version that has actually been deploying this site, rather than
|
||||||
# silently changing it. Bumping the container to node 22 is the
|
# silently changing it. Moving the container to node 22 so the
|
||||||
# alternative; it is a bigger change and is not what this issue is
|
# wrangler pin can advance is tracked in #21.
|
||||||
# for.
|
|
||||||
- name: Install Wrangler
|
- name: Install Wrangler
|
||||||
# wrangler 4.86.0, 2026-08-09
|
# wrangler 4.86.0, 2026-08-09
|
||||||
run: npm install -g wrangler@4.86.0
|
run: npm install -g wrangler@4.86.0
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
# 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
|
|
||||||
# isolates one hypothesis and surfaces as its own status context.
|
|
||||||
#
|
|
||||||
# Round 1 (2d328e7):
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
#
|
|
||||||
# -> the pinned alpine image, the prerequisite step and the site build are all
|
|
||||||
# fine; upload-artifact v4 is what broke the build job on main.
|
|
||||||
#
|
|
||||||
# Round 2 (602fd60):
|
|
||||||
#
|
|
||||||
# build (deploy.yml, upload v3.2.2-node20) success 20s
|
|
||||||
# q1 upload-artifact v3.2.1 (node16) success 7s
|
|
||||||
# q2 upload-artifact v3.2.1-n20 (node20) success 22s
|
|
||||||
# q3 full build + upload v3.2.2-node20 success 11s
|
|
||||||
# q4 download v3.1.0-node20 + wrangler install failure 43s
|
|
||||||
#
|
|
||||||
# -> build green on every v3 upload; a second, separate failure on the deploy
|
|
||||||
# side.
|
|
||||||
#
|
|
||||||
# Round 3 (07af755):
|
|
||||||
#
|
|
||||||
# build (deploy.yml, upload v3.2.1) success 8s
|
|
||||||
# r1 wrangler install + invoke, no artifacts failure 7s
|
|
||||||
# r2a/r2b artifact round trip, v3.2.1/v3.0.2 success 12s / 2s
|
|
||||||
# r3a/r3b artifact round trip, node20 builds success 8s / 2s
|
|
||||||
#
|
|
||||||
# -> the artifact round trip is sound in both pairs; wrangler is the second
|
|
||||||
# break. Reproduced locally in the pinned node image: `npm install -g
|
|
||||||
# wrangler@4.120.0` exits 0 with EBADENGINE warnings, then wrangler itself
|
|
||||||
# exits 1 with "Wrangler requires at least Node.js v22.0.0. You are using
|
|
||||||
# v20.20.2." Unpinned `npm install -g wrangler` on that same image resolves
|
|
||||||
# to 4.86.0, because npm picks the newest version the running node
|
|
||||||
# satisfies -- so 4.86.0 is what has actually been deploying this site, and
|
|
||||||
# that is what deploy.yml now pins.
|
|
||||||
#
|
|
||||||
# Round 4 is the full rehearsal of both jobs end to end with the corrected
|
|
||||||
# pins, stopping one step short of publishing.
|
|
||||||
name: probe
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- pin-deploy-refs-observable
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# Producer: identical to the build job in deploy.yml.
|
|
||||||
s1-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
|
|
||||||
# actions/upload-artifact v3.2.1, 2026-08-09
|
|
||||||
- uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
|
|
||||||
with:
|
|
||||||
name: site-dry
|
|
||||||
path: site.tar.gz
|
|
||||||
|
|
||||||
# Consumer: identical to the deploy job in deploy.yml, except that the
|
|
||||||
# final step prints wrangler's view of the project instead of running
|
|
||||||
# `wrangler pages deploy`. Same pinned image, same pinned action, same
|
|
||||||
# pinned wrangler version, same extracted tree. Needs no token and
|
|
||||||
# publishes nothing.
|
|
||||||
s2-deploy-dryrun:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: s1-build
|
|
||||||
container:
|
|
||||||
# node 20.20.2-bookworm, 2026-08-09
|
|
||||||
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
|
|
||||||
steps:
|
|
||||||
# actions/download-artifact v3.0.2, 2026-08-09
|
|
||||||
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
|
|
||||||
with:
|
|
||||||
name: site-dry
|
|
||||||
- run: tar -xzf site.tar.gz
|
|
||||||
- run: test -f public/index.html
|
|
||||||
# wrangler 4.86.0, 2026-08-09
|
|
||||||
- run: npm install -g wrangler@4.86.0
|
|
||||||
- run: wrangler --version
|
|
||||||
- run: wrangler pages deploy --help
|
|
||||||
26
TODO.md
26
TODO.md
@@ -14,7 +14,8 @@ pre-1.0
|
|||||||
|
|
||||||
No git tags. The site is live and now has the scripts-to-rule-them-all scaffold
|
No git tags. The site is live and now has the scripts-to-rule-them-all scaffold
|
||||||
(`Makefile`, `script/`, `Dockerfile`, `check.yml`); still missing `LICENSE` and
|
(`Makefile`, `script/`, `Dockerfile`, `check.yml`); still missing `LICENSE` and
|
||||||
policy files.
|
policy files. Every external reference in the repo is now pinned by
|
||||||
|
cryptographic hash (or, for the wrangler CLI install, an exact version).
|
||||||
|
|
||||||
# Next Step
|
# Next Step
|
||||||
|
|
||||||
@@ -24,6 +25,21 @@ Update `README.md` accordingly.
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-08-09: hash-pinned every external reference in
|
||||||
|
`.gitea/workflows/deploy.yml` (closes #7): both job container images are
|
||||||
|
pinned by digest, all three `uses:` are pinned by 40-hex commit SHA, and the
|
||||||
|
wrangler install is pinned to an exact version. The abandoned
|
||||||
|
`klakegg/hugo:ext-alpine` image is gone: the build job now runs on the same
|
||||||
|
pinned `alpine` digest the `Dockerfile` uses, with a pre-checkout
|
||||||
|
`apk add nodejs git tar` step (the Actions runner needs `node` inside the job
|
||||||
|
container to execute JavaScript actions), an explicit `shell: sh` default,
|
||||||
|
then `script/bootstrap` and `script/test`. The `deploy` job is guarded with
|
||||||
|
`if: github.ref_name == 'main'` so it can never publish from a branch. Also
|
||||||
|
dropped the dead `feat/initial-site` push trigger and reindented the file to
|
||||||
|
4-space YAML to match `check.yml`. This is the second attempt; the first broke
|
||||||
|
the deploy and was reverted, so this one was verified by temporarily
|
||||||
|
triggering the workflow on the PR branch and iterating until the `build` job
|
||||||
|
ran green for real
|
||||||
- 2026-07-25: added the scripts-to-rule-them-all scaffold (closes #4): `script/`
|
- 2026-07-25: added the scripts-to-rule-them-all scaffold (closes #4): `script/`
|
||||||
entrypoints, `Makefile` shims, a Hugo `Dockerfile` (sha256-pinned alpine) plus
|
entrypoints, `Makefile` shims, a Hugo `Dockerfile` (sha256-pinned alpine) plus
|
||||||
`.dockerignore` that runs `make check`, `.gitea/workflows/check.yml` running
|
`.dockerignore` that runs `make check`, `.gitea/workflows/check.yml` running
|
||||||
@@ -40,9 +56,11 @@ Update `README.md` accordingly.
|
|||||||
|
|
||||||
# Future Steps
|
# Future Steps
|
||||||
|
|
||||||
- Pin the images and actions in `deploy.yml` by sha256
|
- Move the artifact actions to v4 once this Gitea Actions instance serves the v4
|
||||||
(`klakegg/hugo:ext-alpine`, `node:20`, `actions/checkout`,
|
artifact protocol; they are pinned on the deprecated v3 line because v4 fails
|
||||||
`upload`/`download-artifact` are all unpinned)
|
here (#20)
|
||||||
|
- Move the deploy container to a pinned node 22 so the wrangler pin can advance
|
||||||
|
past 4.86.0 (#21)
|
||||||
- Rework README.md into the standard sections: Description, Getting Started,
|
- Rework README.md into the standard sections: Description, Getting Started,
|
||||||
Rationale, Design, TODO, License, Author (currently About, Contributing,
|
Rationale, Design, TODO, License, Author (currently About, Contributing,
|
||||||
Technical Details, License)
|
Technical Details, License)
|
||||||
|
|||||||
Reference in New Issue
Block a user